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

如何对传入泛型函数的抽象类与派生实例进行类型检查?

解决方案

基础方案:使用type实现类型约束

将类参数的类型从Type[T]改为type,结合TypeVar约束实例与类的继承关系,再通过运行时isinstance检查确保类型安全:

from abc import ABC, abstractmethod
from typing import TypeVar

T = TypeVar('T')

def register(klass: type[T], instance: T):
    if not isinstance(instance, klass):
        raise TypeError(f"实例必须是{klass}或其子类的实例")
    print("正在注册类", klass, "与实例", instance)

class MyAbstractClass(ABC):
    @abstractmethod
    def foo(self) -> None:
        pass

class MyClass(MyAbstractClass):
    def foo(self) -> None:
        print("执行foo方法")

register(MyClass, MyClass())  # 类型检查通过
register(MyAbstractClass, MyClass())  # 类型检查通过,运行时符合要求

print(isinstance(MyClass(), MyAbstractClass)) # 输出为True

type[T](Python 3.9+支持,旧版本可替换为Type[T])兼容所有类(包括抽象类),同时通过TypeVar绑定确保实例属于类的派生类型,既解决了Mypy的抽象类报错问题,又保留了类型约束。

Protocol方案(推荐)

通过定义Protocol明确类的行为,确保类支持实例检查,同时严格约束实例与类的继承关系:

from abc import ABC, abstractmethod
from typing import TypeVar, Protocol, runtime_checkable

T = TypeVar('T')

@runtime_checkable
class ClassWithInstanceCheck(Protocol[T]):
    """支持实例检查的类协议"""
    def __instancecheck__(self, instance: object) -> bool:
        ...

def register(klass: ClassWithInstanceCheck[T], instance: T):
    if not isinstance(instance, klass):
        raise TypeError(f"实例必须是{klass}或其子类的实例")
    print("正在注册类", klass, "与实例", instance)

class MyAbstractClass(ABC):
    @abstractmethod
    def foo(self) -> None:
        pass

class MyClass(MyAbstractClass):
    def foo(self) -> None:
        print("执行foo方法")

register(MyClass, MyClass())  # 类型检查通过
register(MyAbstractClass, MyClass())  # 类型检查通过
print(isinstance(MyClass(), MyAbstractClass)) # 输出为True

所有Python类默认实现了__instancecheck__方法,因此抽象类和具体类都能符合协议要求。该方案通过Protocol的类型绑定,既满足了接收抽象类的需求,又严格约束了实例必须是类的派生类型。

原方案报错原因

原方案使用Type[T]时,Mypy默认要求T是可实例化的具体类,因此传入抽象类会触发type-abstract错误。但Python运行时允许抽象类参与isinstance检查,调整类型注解即可匹配运行时实际行为。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 00:15:03