← 中文资源

简体中文版本

Python — 字典查找触发 KeyError

定位缺失键,区分键不存在与值为 None,并在默认值、边界校验和显式错误之间做出选择。

阅读英文原文

回溯指向表达式,不是原因

KeyError 回溯指向 data['tenant_id'],但原因可能是上游服务改了字段名、YAML 缩进不同,或某个分支构造字典时漏了键。查找前打印可用键和对象类型。缺失键是症状,为什么缺失才是缺陷。

payload = {"tenant": "acme", "user": None}
tenant = payload["tenant_id"]  # KeyError: 'tenant_id'

键存在但值为 None 时行为不同:payload["user"]["name"] 抛出 TypeError 而不是 KeyError,因为 None 不可下标。要分别处理这两种情况。

选择正确的缺失策略

缺失无效时,在边界处校验并抛出清晰错误:

REQUIRED = ("tenant_id", "user_id")

missing = [key for key in REQUIRED if key not in payload]
if missing:
    raise ValueError(f"missing required fields: {', '.join(missing)}")

缺失有效时,使用 dict.get(key, default) 或 collections.defaultdict,并在类型和测试中明确默认值。不要把通用 {} 默认值扩散到代码各处,它会掩盖畸形负载,并在远离源头的位置产生错误。

from collections import defaultdict

counts = defaultdict(int)
counts["errors"] += 1

当所有缺失键都有相同且有意义的默认值时,defaultdict 合适。对必需业务字段不合适,缺失应当响亮失败。

校验形状,而不只是一个键

如果字典来自 JSON,使用 Pydantic 等模式校验器或手写检查,把契约显式化。在边界校验一次,把类型化对象传给后续代码。这样能把散落的 KeyError 变成带字段路径的结构化校验错误。对配置,应在启动时因缺少必需环境变量失败,而不是等到第一个使用它的请求。

修复并验证

修复方式是边界校验必填键,并为可选键选择显式策略。用测试验证:从负载中删除键,断言清晰的校验错误;再测试键存在但值为 None。重跑原始失败输入,确认得到领域错误而不是回溯。