Python中如何用Callable为相同签名的函数统一标注类型?
问题原因
你写的代码相当于在同一作用域下两次定义了同名变量f:第一次是标注类型时声明了变量f,第二次是def f定义函数时再次给f赋值,因此触发mypy的重复定义报错。Python 的def语句本身就是赋值操作,无法直接复用提前写好的变量类型标注。
实现方案
下面两种是常用的无侵入、兼容mypy的实现方案:
方案1:类型别名 + 函数赋值
提前给函数签名定义统一的类型别名,定义函数后再赋值给带类型标注的变量即可,mypy会自动校验函数实现是否符合签名要求:
from typing import Callable # 统一定义函数签名的类型别名 IntBinaryOp = Callable[[int, int], int] # 先定义函数 def _add(x, y): return x + y # 赋值给带类型标注的变量,自动完成类型校验 add: IntBinaryOp = _add def _multiply(x, y): return x * y multiply: IntBinaryOp = _multiply
这种写法下mypy会自动校验函数参数、返回值是否匹配类型要求,调用时也会做类型检查。
方案2:类型标注装饰器
如果不想额外定义下划线开头的中转函数,可以写一个纯类型层面的装饰器,批量给同签名函数加类型:
from typing import Callable, TypeVar IntBinaryOp = Callable[[int, int], int] T = TypeVar("T", bound=Callable) def with_type(func_type: T) -> Callable[[Callable], T]: # 运行时无任何逻辑,仅做类型传递 def decorator(func: Callable) -> T: return func return decorator # 直接用装饰器标注,不需要额外写参数返回值类型 @with_type(IntBinaryOp) def add(x, y): return x + y @with_type(IntBinaryOp) def multiply(x, y): return x * y
这种写法更适合批量处理大量同签名函数,代码更简洁。Python 3.10及以上版本可以直接运行上述代码,低版本可以额外导入typing_extensions.TypeAlias标注类型别名提升兼容性。
内容的提问来源于stack exchange,提问作者sevan
相关产品推荐
相关产品推荐

