如何对传入泛型函数的抽象类与派生实例进行类型检查?
解决方案
基础方案:使用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
相关产品推荐
相关产品推荐

