Literal用于函数参数类型提示时需用typing.Literal包裹固定字面量,仅在静态分析阶段生效,不提供运行时校验;正确写法如def set_mode(mode: Literal["fast", "slow", "debug"]) -> None:,传入非字面量或非法值会触发类型警告,但运行时仍需手动校验。

Literal 用于函数参数类型提示时怎么写
直接用 typing.Literal 包裹具体字符串字面量,就能让类型检查器(如 mypy、PyCharm)识别该参数只接受这几个固定值。它不是运行时校验,只在静态分析阶段起作用。
常见错误是误以为加了 Literal 就能自动拦截非法输入——实际运行时不会抛错,必须额外做值检查。
- 正确写法:
def set_mode(mode: Literal["fast", "slow", "debug"]) -> None: - 传入
"fast"或"debug"会被识别为合法;传入"normal"或变量user_input(哪怕值恰好是"fast")会触发类型警告 - 支持混合类型:
Literal["on", "off", 1, 0],但不推荐混用字符串和数字,易引发逻辑歧义
为什么 mypy 不报错但程序仍跑通了
Literal 是纯类型提示机制,Python 解释器完全忽略它。mypy 报错说明你启用了类型检查且配置正确;没报错可能因为:
- 没运行 mypy(比如只执行
python script.py) - mypy 被配置为忽略该文件或该行(例如有
# type: ignore) - 参数实际传入的是变量而非字面量,例如
set_mode(user_choice)—— 此时 mypy 只能按变量声明的类型判断,无法追踪运行时值
若需运行时约束,得手动加判断:if mode not in ("fast", "slow", "debug"): raise ValueError(...)
Literal 和 Union[str, "a", "b"] 有什么区别
没有 Union[str, "a", "b"] 这种写法——字符串字面量不能直接当类型和 str 做联合。正确的等价写法是:
-
Literal["a", "b"]:仅允许两个确切字符串 -
Union[Literal["a"], Literal["b"]]:等价于上式,但冗余,不建议 -
Union[Literal["a", "b"], int]:允许"a"、"b"或任意整数 -
str:允许所有字符串,包括"a"、"b"、"c"……无法限定范围
混淆点常出现在想“既接受固定值又接受其他字符串”,这时 Literal 不适用,得用 str + 运行时校验,或引入更复杂的协议(如 Protocol)
嵌套结构里怎么用 Literal(如 dict 或 TypedDict)
可以出现在任意类型注解位置,包括键名、值类型、字段定义。关键是让类型检查器能推导出字面量约束。
- 字典值限制:
config: Dict[str, Literal["enabled", "disabled"]] - TypedDict 字段:
class Options(TypedDict): log_level: Literal["INFO", "WARN", "ERROR"] use_cache: Literal[True, False] - 注意:字典键不能直接用
Literal限定(如Dict[Literal["host", "port"], str]合法但无实际约束力,因为键是运行时动态的)
复杂嵌套容易让 mypy 推导失败,建议拆成独立类型别名,提高可读性和检查精度










