Python TypedDict 怎样标记部分必填字段
来源:17golang原创
时间:2026-10-18 14:10:35 431浏览 收藏
Python TypedDict 中只让部分字段必填,可以使用 total=False 配合 Required[T];如果大部分字段必填,则保留默认 total=True,只给可缺省字段加 NotRequired[T]。这些标记约束的是键是否必须存在,不能代替运行时输入校验,也不等同于值是否允许 None。
以下用上传元数据 UploadSpec 展示最小写法与变体,不涉及实际文件上传。示例面向 Python 3.11 及以上。官方文档:https://docs.python.org/3/library/typing.html#typing.TypedDict;Required 与 NotRequired 的设计说明见 https://peps.python.org/pep-0655/。
先写出只有标识必填的最小声明
from typing import Required, TypedDict
class UploadSpec(TypedDict, total=False):
# 即使其余字段可缺省,object_id 也必须存在且为字符串。
object_id: Required[str]
caption: str
expires_at: str | None
# 只有标识也满足契约;不需要为可缺省键补 None。
minimal: UploadSpec = {"object_id": "asset-17"}
object_id 是必填字符串;caption 可以整个键不出现,出现时应为字符串;expires_at 也可以不出现,出现时允许字符串或 None。这里的约束供静态类型工具理解,不是字典创建时自动执行的验证规则。
可以把这份声明当作三个位置的契约:object_id 属于必填键,caption 与 expires_at 属于可缺省键。total=False 提供本类声明字段的缺省规则,Required 在单个字段上明确覆盖它。

把键是否存在和取值是否为空分开
两个维度要分别回答:字典里是否必须有这个键?有键时允许什么值?在默认 total=True 的 TypedDict 中,expires_at: str | None 仍然要求 expires_at 存在,只是值可以为 None;它不能表达“键可以不传”。
| 字段声明(默认 total=True) | 键可缺省 | 值可为 None |
|---|---|---|
| value: str | 否 | 否 |
| value: str | None | 否 | 是 |
| value: NotRequired[str] | 是 | 否 |
| value: NotRequired[str | None] | 是 | 是 |
Optional[str] 的含义与 str | None 相同,并不会让键变成可缺省。对于部分更新一类接口,“不提供字段”可能代表保持原设置,“提供 None”可能代表清空设置,但这只是可选择的业务约定,TypedDict 本身不赋予这两种操作任何服务端含义。
按必填字段比例选择另一种写法
from typing import NotRequired, TypedDict
class UploadSpec(TypedDict):
# 默认 total=True,未特别标记的键是必填键。
object_id: str
caption: NotRequired[str]
expires_at: NotRequired[str | None]
这份 UploadSpec 与前面的字段契约相同,只是从“默认全可缺省,单独声明必填”换成“默认全必填,单独声明可缺省”。实际项目选一种更贴近字段比例的写法即可,不必在同一模块里重复定义同名类型。
Required 和 NotRequired 只用于 TypedDict 的字段注解;不要把它们当普通函数参数的必填声明,也不要嵌套成 Required[NotRequired[str]]。函数参数是否必须传入,应由函数签名与默认参数决定。
读取可缺省字段时保留存在性判断
下面是一段可独立保存的完整示例。describe_expiry 只描述元数据,没有请求外部服务,也不解析日期、设置过期任务或更改存储系统。
from typing import NotRequired, TypedDict
class UploadSpec(TypedDict):
# 必填标识与两项可缺省元数据分别声明。
object_id: str
caption: NotRequired[str]
expires_at: NotRequired[str | None]
def describe_expiry(spec: UploadSpec) -> str:
# 先判断键存在,避免把“未提供”与“显式清空”混为一谈。
if "expires_at" not in spec:
return "未提供过期设置"
expiry = spec["expires_at"]
if expiry is None:
return "显式清空过期设置"
return f"过期时间:{expiry}"
omitted: UploadSpec = {"object_id": "asset-17"}
cleared: UploadSpec = {"object_id": "asset-18", "expires_at": None}
scheduled: UploadSpec = {
"object_id": "asset-19",
"expires_at": "2027-01-10T08:00:00Z",
}
print(describe_expiry(omitted))
print(describe_expiry(cleared))
print(describe_expiry(scheduled))
这里用 "expires_at" in spec 区分缺键,再判断值是否为 None。若直接 spec["expires_at"],缺键时普通字典仍可能抛 KeyError;如果直接 spec.get("expires_at"),缺键与值为 None 都会得到 None,无法保留本例所需区别。

将完整片段保存为 typed_metadata.py 后,读者可在 Python 3.11 及以上运行:
# 只运行字典读取示例,不执行上传操作。 python3 typed_metadata.py
本文没有执行示例。按三个输入推导的预期文本如下;它只是运行时函数行为,不代表静态类型检查已经通过:
未提供过期设置 显式清空过期设置 过期时间:2027-01-10T08:00:00Z
明确版本与运行时边界
Python 3.11 起可以从 typing 导入 Required 与 NotRequired。维护更早版本时,需采用兼容的 typing_extensions,并按其支持范围配置;PEP 655 特别提醒老版本方案中 TypedDict 也应从 typing_extensions 导入,不要随意混用新限定符和旧 typing.TypedDict。本文不安装依赖或运行类型检查工具。
TypedDict 的值在运行时仍是普通字典。它不会替你拒绝缺少 object_id 的外部 JSON,不会检查 object_id 是不是字符串,也不会补 caption 的默认值。来自网络、文件等不可信输入,需要另设运行时解析和校验入口,再交给声明了契约的业务函数;单纯加注解或做类型断言不能把不合法数据变合法。
静态工具的诊断文字和部分读取提示会因工具及配置不同而变化,不能把一次 python3 执行成功当成类型约束已验证。反过来,类型符合声明也不意味着字符串就是有效日期或真实对象标识。
常见问题速查
NotRequired 会自动给字段设置默认值吗?
不会,它只说明键允许不出现。需要默认值时,应在读取或构造逻辑里显式定义,并决定是否要区分缺键与 None。
外层字段必填,内部字段也会跟着必填吗?
不会递归套用。嵌套值如果又是一个 TypedDict,应由内部类型单独定义其字段规则;外层 Required 只约束那个外层键。
子类写 total=False 会把继承的必填键全部变为可缺省吗?
不会,total 作用于当前类体新声明的字段,不会批量改写继承字段的既有必填性。避免通过重新声明同名字段强行改变契约。
最小选择规则是:少数必填用 total=False 加 Required,少数可缺省用默认 total 加 NotRequired;允许 None 则另写值联合类型。把这两层分清,部分必填字段的注解就不必依赖模糊的“可选”一词。
-
417 收藏
-
371 收藏
-
394 收藏
-
文章 · python教程 | 56分钟前 | 缓存 · 垃圾回收 · python · 内存管理 · Python 内存缓存 对象生命周期 weakref.WeakValueDictionary 弱引用缓存185 收藏
-
318 收藏
-
179 收藏
-
426 收藏
-
文章 · python教程 | 1小时前 | 标准库 · 文件读取 · 编码 · python · Python pathlib UnicodeDecodeError Path.read_text 文本编码101 收藏
-
210 收藏
-
文章 · python教程 | 1小时前 | 队列 · Python教程 · asyncio · Python 消费者 asyncio.Queue Queue.shutdown QueueShutDown133 收藏
-
296 收藏
-
449 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习