如何无需枚举让类实例作为泛型值通过Mypy检查?
问题现象
我发现一个实用的小特性:如果把类实例赋值给枚举成员,那么在Literal或泛型类型中使用这个实例时,mypy不会报错;但直接用普通变量的话,就会触发"Variable not allowed in type expression"错误。用这种方式标识对象类型在某些场景下很方便,示例代码如下:
from enum import Enum from typing import Literal, Generic class MyKlass(): pass my_val = MyKlass() class MyEnum(Enum): val = my_val Literal[MyEnum.val] # mypy 不报错 Literal[my_val] # mypy 报错:"Variable not allowed in type expression"
基于这个特性,我实现了让泛型接受任意值的写法:
class MyEnum(Enum): val = my_val class MyClass(Generic[T]): pass MyClass[MyEnum.val] # 无问题
更优实现方式
不用额外定义枚举类,直接用typing.Final标记变量为常量即可。mypy会把Final修饰的变量认定为编译时常量表达式,允许它出现在Literal或泛型类型参数中,代码更简洁:
from typing import Final, Literal, Generic class MyKlass(): pass # 用Final标记变量为不可变常量 my_val: Final[MyKlass] = MyKlass() # 直接使用变量,mypy不报错 Literal[my_val] class MyClass(Generic[T]): pass # 泛型中直接使用Final变量 MyClass[my_val]
原理说明
mypy对类型表达式的核心要求是必须为常量表达式:
- 枚举成员本身就是不可变的常量,天然符合要求
Final标记的变量会被mypy判定为不可修改的常量,同样满足类型表达式的规则
这种方式省去了冗余的枚举定义,同时完美契合“避免将值作为函数参数传入,聚焦静态类型检查”的需求。
内容的提问来源于stack exchange,提问作者Rob
相关产品推荐
相关产品推荐

