我想将以下内容重构为类型安全的内容。我现在给出了 mypy“与超类型不兼容”错误。
我理解这是由于里氏替换原则:
- 子类型中方法参数的逆变。
- 子类型中返回类型的协方差。
也就是说(如果我理解正确的话),我可以返回A
or a subtype of A
,但我只能通过A
or a 超型 of A
(两者都不会有b
属性)到 B.add。
所以,我“不能”做我一直在做的事情,我正在寻找一种重构方法(更多代码见下文)。
# python 3.7
class A:
def __init__(self, a: int) -> None:
self.a = a
def add(self, other: "A") -> "A":
return type(self)(a=self.a + other.a)
class B(A):
def __init__(self, a: int, b: int) -> None:
super().__init__(a=a)
self.b = b
def add(self, other: "B") -> "B": # Argument 1 of "add" incompatible with supertype "A"
return type(self)(a=self.a + other.a, b=self.b + other.b)
我唯一想到的是某种父母类型A
and B
没有add
method.
class SuperAB:
# doesn't add
pass
class A(SuperAB):
# has add method
pass
class B(SuperAB):
# has add method
pass
这看起来很混乱,但如果这是“Pythonic”要做的事情,我会同意的。我只是想知道是否还有其他方法(除了 # type:ignore 之外)。
解决方案:
在玩了“打地鼠”并遇到各种类型错误后,我在 StackOverflow 答案的帮助下得到了这个:
T = TypeVar("T")
class A(Generic[T]):
def __init__(self, a: int) -> None:
self.a = a
def add(self, other: T) -> "A":
return type(self)(a=self.a + getattr(other, "a"))
class B(A["B"]):
def __init__(self, a: int, b: int) -> None:
super().__init__(a=a)
self.b = b
def add(self, other: T) -> "B":
return type(self)(
a=self.a + getattr(other, "a"), b=self.b + getattr(other, "b")
)
请注意,我做不到self.a + other.a
因为我会看到一个"T" has no attribute "a"
错误。上面的方法可行,但感觉这里的受访者比我知道的更多,所以我采取了他们的real建议并重构。
我见过足够多的人知道是正确的一条建议是“B 应该haveA,不是beA。”我承认这超出了我的理解范围。Bhas和 int (实际上是两个,B.a 和 B.b)。这些整数会做整数所做的事情,但是,为了B.add(B)
,我必须以某种方式将这些整数放入另一个 B 中,如果我希望“以某种方式”具有多态性,我就回到了开始的地方。我显然遗漏了一些关于 OOP 的基本知识。