Python中如何为装饰器的Callable签名标注子类兼容的类型?
解决装饰器接受A子类作为第一个参数的类型注解问题
你遇到的报错本质是函数类型的逆变特性导致的:Callable[[A], str]要求函数能接受任意A类型的实例,但funcb仅能接受更具体的B(A的子类)类型实例,类型检查器认为这种赋值存在安全风险,因此报错。
解决方案:使用泛型约束参数类型
通过TypeVar绑定A类,定义泛型类型来约束装饰器接受的函数签名,确保第一个参数是A的子类:
from typing import Callable, TypeVar # 定义泛型变量T,限定为A或其子类 T = TypeVar('T', bound='A') class A: pass class B(A): pass def wrapper(func: Callable[[T], str]) -> Callable[[T], str]: def inner(self: T) -> str: # 此处添加装饰器逻辑 result = func(self) return f"装饰后结果:{result}" return inner @wrapper # 类型检查通过 def funca(self: A) -> str: return "a" @wrapper # 不再报错 def funcb(self: B) -> str: return "b"
原理说明
TypeVar('T', bound='A')限定了T必须是A或它的子类,装饰器的参数func: Callable[[T], str]表示接受一个以A子类为第一个参数、返回str的函数,完美匹配funcb的签名,同时保留类型检查的安全性。
可选方案:使用Protocol定义可调用协议
如果需要更灵活的类型定义,可以通过Protocol自定义符合要求的可调用类型:
from typing import Protocol, TypeVar T = TypeVar('T', bound='A') class A: pass class B(A): pass # 定义协议,要求函数第一个参数为A的子类 class ASubclassCallable(Protocol[T]): def __call__(self: T) -> str: ... def wrapper(func: ASubclassCallable[T]) -> ASubclassCallable[T]: def inner(self: T) -> str: return func(self) return inner @wrapper def funca(self: A) -> str: return "a" @wrapper def funcb(self: B) -> str: return "b"
内容的提问来源于stack exchange,提问作者VIP Trollik
相关产品推荐
相关产品推荐

