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

如何编写接受父类型任意子类型实例的Python类型提示?

如何用类型提示接受某类型的任意子类型实例

要实现接受SuperType任意子类型实例的类型提示,核心是利用协变TypeVar兼容子类实例与父类类型的赋值关系,同时通过类型约束区分实例方法和静态方法。

问题根源

你遇到的MyPy报错,是因为默认的TypeVar是不变的:Callable[[Child, int], None](子类实例方法的签名)无法被视为Callable[[Parent, int], None](父类实例方法的签名)的子类型。而我们需要的是允许子类实例替代父类实例的协变关系。

解决方案

1. 定义协变的TypeVar

将SuperType声明为协变,这样子类实例可以被安全地赋值给期望父类实例的参数:

from typing import *

CallbackArgs = ParamSpec('CallbackArgs')
CallbackReturn = TypeVar('CallbackReturn')
# 声明协变TypeVar,允许子类实例替代父类实例
SuperType = TypeVar('SuperType', covariant=True)

2. 调整装饰器的类型签名

修改check函数的返回类型,让inner接受的函数第一个参数是SuperType(而非Type[SuperType]),这样就能匹配任意子类型的实例:

def check(func: Callable[Concatenate[SuperType, CallbackArgs], CallbackReturn]) \
        -> Callable[[Callable[Concatenate[SuperType, CallbackArgs], CallbackReturn]], None]:
    def inner(function: Callable[Concatenate[SuperType, CallbackArgs], CallbackReturn]) -> None:
        return None
    return inner

3. 验证代码

现在你的示例代码可以通过MyPy检查,同时能正确约束类型:

class Parent:
    def func(self, a: int) -> None:
        ...

class Child(Parent):
    # 类型检查通过:Child实例是Parent的子类型,符合协变要求
    @check(Parent.func)
    def func(self, a: int) -> None:
        ...

4. 检测静态方法的错误使用

如果尝试将check用于静态方法,MyPy会直接报错,因为静态方法的第一个参数不是实例类型,无法匹配SuperType的约束:

class Child(Parent):
    @staticmethod
    @check(Parent.func)  # MyPy报错:静态方法的签名不匹配期望的实例方法签名
    def func(a: int) -> None:
        ...

关键说明

  • 协变TypeVar的作用:当SuperType被标记为协变时,Callable[[Child, ...], ...]会被视为Callable[[Parent, ...], ...]的子类型,符合面向对象中"里氏替换原则"的类型要求。
  • 无需使用Type[SuperType]:Type[SuperType]表示类本身(比如Parent或Child类对象),而我们需要的是类的实例,所以直接用SuperType即可。

内容的提问来源于stack exchange,提问作者mutableVoid

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 06:18:30