登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  python教程

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 在单个字段上明确覆盖它。

UploadSpec的必填键、可缺省键和total规则关系
图1:字段契约静态说明图。分组区分声明规则与三个字段,连线表示规则归属,不是执行顺序或运行截图。

把键是否存在和取值是否为空分开

两个维度要分别回答:字典里是否必须有这个键?有键时允许什么值?在默认 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,无法保留本例所需区别。

expires_at存在性与值域的静态关系
图2:存在性和值域说明图。缺键、None 与字符串分别是可缺省字段的不同状态;图中关系只解释 describe_expiry 的判断依据,不是实测输出。

将完整片段保存为 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 则另写值联合类型。把这两层分清,部分必填字段的注解就不必依赖模糊的“可选”一词。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>