mypy:“__add__”的签名与超类型 "tuple" 不兼容 - 但与 __sub__ 一切正常
mypy: Signature of "__add__" incompatible with supertype "tuple" - but everything fine with __sub__
我正在制作一个简单的矢量 class,我正在努力了解 mypy 如何处理我的 __add__
和 __sub__
方法(特别是 mypy 中的区别在下面的代码 1 和代码 3 中输出。
代码 1:
from typing import NamedTuple
class Vector(NamedTuple):
x: float
y: float
def __add__(self, other: Vector) -> Vector:
return Vector(self.x + other.x, self.y + other.y)
代码2:
from typing import NamedTuple
class Vector(NamedTuple):
x: float
y: float
def __add__(self, other: object) -> Vector:
if not isinstance(other, Vector):
return NotImplemented
return Vector(self.x + other.x, self.y + other.y)
代码 3:
from typing import NamedTuple
class Vector(NamedTuple):
x: float
y: float
def __sub__(self, other: Vector) -> Vector:
return Vector(self.x - other.x, self.y - other.y)
使用代码 1,当 运行 mypy:
时出现以下错误
error: Signature of "__add__" incompatible with supertype "tuple"
.
使用代码 2 和代码 3 我没有错误。
为什么我收到代码 1 而不是代码 2 的错误?
其次(这让我更加困惑),为什么我从代码 3 中得到的错误与我在代码 1 中得到的错误不同?
非常感谢。
编辑
我想答案是因为 superclass NamedTuple
允许添加,但指定第二个参数是代码 2 允许的类型 object
,而代码 1 不允许't.
而且 mypy 是用代码 3 找到的,因为 NamedTuple
没有实现 __sub__
。
Liskov substitution principle (LSP) 声明子类型的对象应该始终可用于代替超类型的对象。在这种情况下,超类型是 tuple
,它有一个 __add__
方法接受另一个 tuple
.
在您的代码 #1 中,您重写了此 __add__
方法,但您重写的方法不能用于代替原始方法,因为它只接受 Vector
,而不接受任意 tuple
。所以这违反了 LSP,因此是类型错误。
您的代码 #2 没有错误,因为您覆盖的 __add__
方法接受任何 object
,因此原始方法的任何有效参数也是新方法的有效参数。这意味着可以使用子类型代替超类型,因此不会违反 LSP。
您的代码 #3 没有错误,因为您的 __sub__
方法没有覆盖超类型的任何方法 - 未定义 tuple
的减法 - 并且添加新方法不违反LSP,因为当使用对象代替超类型时,根本不会调用这个新方法。
我正在制作一个简单的矢量 class,我正在努力了解 mypy 如何处理我的 __add__
和 __sub__
方法(特别是 mypy 中的区别在下面的代码 1 和代码 3 中输出。
代码 1:
from typing import NamedTuple
class Vector(NamedTuple):
x: float
y: float
def __add__(self, other: Vector) -> Vector:
return Vector(self.x + other.x, self.y + other.y)
代码2:
from typing import NamedTuple
class Vector(NamedTuple):
x: float
y: float
def __add__(self, other: object) -> Vector:
if not isinstance(other, Vector):
return NotImplemented
return Vector(self.x + other.x, self.y + other.y)
代码 3:
from typing import NamedTuple
class Vector(NamedTuple):
x: float
y: float
def __sub__(self, other: Vector) -> Vector:
return Vector(self.x - other.x, self.y - other.y)
使用代码 1,当 运行 mypy:
时出现以下错误error: Signature of "__add__" incompatible with supertype "tuple"
.
使用代码 2 和代码 3 我没有错误。
为什么我收到代码 1 而不是代码 2 的错误?
其次(这让我更加困惑),为什么我从代码 3 中得到的错误与我在代码 1 中得到的错误不同?
非常感谢。
编辑
我想答案是因为 superclass NamedTuple
允许添加,但指定第二个参数是代码 2 允许的类型 object
,而代码 1 不允许't.
而且 mypy 是用代码 3 找到的,因为 NamedTuple
没有实现 __sub__
。
Liskov substitution principle (LSP) 声明子类型的对象应该始终可用于代替超类型的对象。在这种情况下,超类型是 tuple
,它有一个 __add__
方法接受另一个 tuple
.
在您的代码 #1 中,您重写了此 __add__
方法,但您重写的方法不能用于代替原始方法,因为它只接受 Vector
,而不接受任意 tuple
。所以这违反了 LSP,因此是类型错误。
您的代码 #2 没有错误,因为您覆盖的 __add__
方法接受任何 object
,因此原始方法的任何有效参数也是新方法的有效参数。这意味着可以使用子类型代替超类型,因此不会违反 LSP。
您的代码 #3 没有错误,因为您的 __sub__
方法没有覆盖超类型的任何方法 - 未定义 tuple
的减法 - 并且添加新方法不违反LSP,因为当使用对象代替超类型时,根本不会调用这个新方法。