literal是python 3.8+引入的类型提示工具,用于限定变量或参数只能取指定字面量值(如字符串、数字、布尔值),仅在静态类型检查(如mypy)时生效,不提供运行时校验。

Literal 是什么,什么时候该用它
typing.Literal 不是运行时校验工具,它只在类型检查阶段起作用(比如用 mypy 或 IDE 的静态分析)。如果你希望函数调用时“报错阻止传入非法值”,Literal 本身做不到——它不会抛异常,也不会拦截参数。它的价值在于:提前暴露错误、增强 IDE 补全、明确接口契约。
怎么写一个带 Literal 参数的函数
直接在参数注解里用 Literal[...] 列出允许的字面量值即可。支持字符串、数字、布尔、None,但不能是变量或表达式。
示例:
from typing import Literal
<p>def set_mode(mode: Literal["fast", "safe", "debug"]) -> None:
print(f"Mode set to {mode}")</p><p>set_mode("fast") # ✅ 类型检查通过
set_mode("slow") # ❌ mypy 报错:Argument 1 has incompatible type "str"
set_mode(42) # ❌ 同样报错:Expected "fast" | "safe" | "debug"
</p>
注意:Literal 中的每个值必须是 Python 字面量,不能写成 Literal[MODE_FAST](除非 MODE_FAST 是 Final[str] 且被 mypy 识别为常量)。
常见坑:字符串 vs 变量、Union 写法、与 str 混用
容易误以为加了 Literal 就能防止运行时乱传——其实只要绕过类型检查(比如不跑 mypy、用 exec、动态构造字符串),照样能调用成功。
- ❌ 错误写法:
mode: Literal[MY_CONST],其中MY_CONST = "prod"—— mypy 默认不推导这种变量为字面量,需加Final - ✅ 正确写法:
from typing import Final; MY_CONST: Final = "prod",再写Literal[MY_CONST] - ❌ 混用
str和Literal:如mode: str | Literal["auto"],这等价于str,失去限制意义 - ✅ 真正需要扩展时,用
Union[Literal["a", "b"], Literal["c"]]或简写为Literal["a", "b", "c"]
和 enum 对比:选哪个更合适
如果常量有语义分组、可能附带方法或需要迭代,优先用 Enum;如果只是简单标记、追求轻量、且 IDE 补全体验更重要,Literal 更直接。
关键区别:
-
Enum是运行时对象,可is判断、可遍历、可带属性;Literal在运行时完全消失,只剩普通值 -
Literal["red", "blue"]的参数接收的是普通字符串,而Color.RED是枚举成员,类型更重 - mypy 对
Enum成员的检查更严格,但补全不如Literal直观(尤其 VS Code 对 Literal 字符串补全很友好)
别指望 Literal 替代枚举逻辑,也别用它做运行时校验——那是 if mode not in ("a", "b") 或 Pydantic 的事。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











