Python中如何为函数枚举(Function Enums)添加正确类型注解
问题描述
需要为「仅接收固定枚举内定义的函数作为入参」的函数编写类型注解,满足两个核心规则:
- 传入枚举类
FuncEnum的成员时,mypy判定为合法输入,且可正常调用 - 传入未在枚举中定义的外部函数时,mypy抛出类型错误
之前的三种尝试均无法通过类型检查:
- 入参标注为
Callable、默认值设为FuncEnum.FUN1:mypy不认可枚举成员属于Callable类型 - 入参标注为
FuncEnum、直接调用func():mypy判定FuncEnum实例不可调用 - 让
FuncEnum同时继承Callable和Enum:Callable是类型构造器,不能作为运行时父类,会直接导致类型检查逻辑失效
可行解决方案
核心思路是让类型检查器明确识别FuncEnum的实例是可调用对象,无需修改原有业务逻辑,实现代码如下:
from enum import Enum def test1() -> None: print('hi') def test2() -> None: print('hi2') class FuncEnum(Enum): FUN1 = test1 FUN2 = test2 # 显式实现__call__方法,签名和绑定的函数保持一致 def __call__(self) -> None: self.value() def my_annotated_function(func: FuncEnum = FuncEnum.FUN1) -> None: func()
方案说明
- 给
FuncEnum显式实现__call__方法后,mypy会自动识别该枚举类的实例为可调用对象,直接调用func()不会触发类型警告 - 入参类型标注为
FuncEnum后,所有非FuncEnum类型的入参(包括外部自定义的普通函数)都会被mypy判定为非法输入,直接抛出类型错误 - 运行时逻辑和预期完全一致:
__call__方法内部会转调枚举成员绑定的实际函数,无额外性能开销
验证结果
- 合法调用
my_annotated_function(FuncEnum.FUN1):mypy检查通过,运行正常输出hi - 非法调用测试:
mypy会直接抛出类型错误:def random_function(): pass my_annotated_function(random_function)Argument 1 to "my_annotated_function" has incompatible type "Callable[[], None]"; expected "FuncEnum",完全符合要求。
轻量替代方案(不修改枚举类)
如果不想修改枚举类实现,可以在函数内部显式调用枚举值的value属性拿到实际函数,此时直接将入参标注为FuncEnum即可通过类型检查:
def my_annotated_function(func: FuncEnum = FuncEnum.FUN1) -> None: func.value()
该方案同样满足类型检查规则,唯一区别是函数内部需要通过.value取实际绑定的函数,运行逻辑无差异。
内容的提问来源于stack exchange,提问作者Ziur Olpa
相关产品推荐
相关产品推荐

