Python类型提示问题:子类与泛型不兼容的mypy报错排查
问题原因
你把类C声明为泛型类,T是绑定A的TypeVar,这意味着实例化C时T会被固定为某个A的子类(比如C[B]、C[A])。但foo方法的默认参数是B(类型为type[B]),如果实例化的是C[A],assistant参数要求是type[A],而type[B]并不兼容type[A]——因为type[B]是type[A]的子类型,反过来不成立,所以mypy会判定默认值类型不匹配。
解决方案
根据你的需求,有三种可行的调整方式:
方案一:给类泛型参数设置默认值
如果希望类C的实例和特定A子类绑定,同时保留默认参数,给泛型参数T设置默认值B。这样当用户不指定T时,默认T=B,默认参数B正好匹配type[T];若指定其他T,则必须显式传递对应类型的参数。
from typing import TypeVar, Generic, Type class A: pass class B(A): pass T = TypeVar('T', bound=A) class C(Generic[T]): def foo(self, assistant: Type[T] = B) -> None: pass # 合法调用 c1 = C() # 等价于C[B] c1.foo() # 使用默认值B c2 = C[A]() c2.foo(A) # 必须显式传递A,否则会报错
方案二:将泛型定义在方法上
如果foo方法不需要和类C的泛型绑定,而是每次调用可以接受任意A的子类,把TypeVar的泛型约束放在方法层面,类C无需声明为泛型类。
from typing import TypeVar, Type class A: pass class B(A): pass T = TypeVar('T', bound=A) class C: def foo(self, assistant: Type[T] = B) -> None: pass # 所有调用均合法 c = C() c.foo(B) c.foo(A) class D(A): pass c.foo(D)
方案三:直接使用Type[A]作为参数类型
如果不需要在方法中使用T的具体类型信息,只是要求参数是A的子类,直接用Type[A]作为参数类型即可——因为type[B]是type[A]的子类型,默认值B完全合法。
from typing import Type class A: pass class B(A): pass class C: def foo(self, assistant: Type[A] = B) -> None: pass # 合法调用 c = C() c.foo() # 使用默认值B c.foo(A) c.foo(B)
内容的提问来源于stack exchange,提问作者Paul Gilmartin
相关产品推荐
相关产品推荐

