You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 11:02:43