所以我的问题是,当我有一个
A
类型的类来做事情并且我使用这些函数作为
subclass(B)
时,它们仍然是类
A
的类型,并且不接受我的类
B
对象作为参数或作为函数签名。
我的问题简化了:
from typing import TypeVar, Generic, Callable
T = TypeVar('T')
class Signal(Generic[T]):
def connect(self, connector: Callable[[T], None]) -> None:
pass
def emit(self, payload: T):
pass
class A:
def __init__(self) -> None:
self.signal = Signal[A]()
def do(self) -> None:
self.signal.emit(self)
def handle_b(b: "B") -> None:
print(b.something)
class B(A):
def __init__(self) -> None:
super().__init__()
self.signal.connect(handle_b)
@property
def something(self) -> int:
return 42
我也可以提供完整的信号类,但这只会分散对问题的注意力。这给我在 mypy 中留下了一个错误:
error: Argument 1 to "connect" of "Signal" has incompatible type Callable[[B], None]; expected Callable[[A], None]
由于信号处理是在
A
子类中实现的
B
不能期望
B
类型对象被返回,即使它显然应该没问题......
遇到的问题在于,在定义
Signal[A]
时,类型提示会变得具体化,并且不知道将来会有
B
子类
A
。
可以通过以下几种方法解决此问题:
1. 使用
TypeVar
绑定到
A
的子类:
from typing import TypeVar, Generic, Callable
T = TypeVar('T', bound='A') # 将 T 限制为 A 的子类
class Signal(Generic[T]):
def connect(self, connector: Callable[[T], None]) -> None:
pass
def emit(self, payload: T):
pass
class A:
def __init__(self) -> None:
self.signal: Signal[A] = Signal() # 明确指定 Signal[A]
def do(self) -> None:
self.signal.emit(self)
def handle_b(b: "B") -> None:
print(b.something)
class B(A):
def __init__(self) -> None:
super().__init__()
self.signal.connect(handle_b) # 现在可以接受 handle_b
@property
def something(self) -> int:
return 42
在这个版本中,
T
被限制为
A
或其任何子类,因此
Signal[A]
可以接受
B
类型的对象。
2. 在子类中重新定义
signal
类型:
from typing import Callable
# ... (Signal 类定义不变)
class A:
def __init__(self) -> None:
self.signal: Signal[A] = Signal()
def do(self) -> None:
self.signal.emit(self)
def handle_b(b: "B") -> None:
print(b.something)
class B(A):
signal: Signal['B'] # 重新定义 signal 类型
def __init__(self) -> None:
super().__init__()
self.signal.connect(handle_b)
@property
def something(self) -> int:
return 42
在这个版本中,我们在
B
类中重新定义了
signal
的类型注释,使其更具体为
Signal['B']
。
这两种方法都可以解决的问题,选择哪种方法取决于的具体需求和代码结构。
标签:python,python-typing,mypy From: 47896283