为何Literal[1,2]合法而Literal[logging.WARNING]不合法?求替代方案
Literal类型标注中logging常量的问题解析
问题背景
运行以下代码可知,1和logging.WARNING的类型均为int:
import logging print(type(1)) print(type(logging.WARNING))
输出:
<class 'int'> <class 'int'>
但在mypy静态检查中,OneOrTwo = Literal[1,2]是合法的,而WarningOrError = Literal[logging.WARNING, logging.ERROR]会报错:Variable 'logging.WARNING' is not valid as a type。
原因分析
mypy对Literal的元素有严格要求:仅接受类型检查阶段就能确定固定值的表达式,包括:
- 直接的字面量(如
1、"test") - 枚举类的成员
- 被
Final标注的常量
1是Python字面量,mypy能确定它的值永远不会变;但logging.WARNING本质是模块级的普通变量(即使运行时它是固定的int值,静态检查时mypy默认认为它可能被重新赋值),因此不符合Literal的元素要求,导致报错。
解决方案
方法一:用Final标注logging常量
通过Final告诉mypy这些变量是不可修改的固定值,即可合法用于Literal:
from typing import Literal, Final import logging # 将logging的常量包装为Final类型 LOG_WARNING: Final[int] = logging.WARNING LOG_ERROR: Final[int] = logging.ERROR WarningOrError = Literal[LOG_WARNING, LOG_ERROR] def a(arg: WarningOrError) -> None: pass
方法二:直接使用常量对应的字面量值
如果能确定logging常量的固定数值(比如logging.WARNING=30、logging.ERROR=40),可以直接用这些数值定义Literal:
from typing import Literal WarningOrError = Literal[30, 40] def a(arg: WarningOrError) -> None: pass
注意:这种方法的缺点是不够直观,若logging库的常量值发生变更(概率极低)会导致类型标注失效。
内容的提问来源于stack exchange,提问作者Vince
相关产品推荐
相关产品推荐

