微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

mypy:“__add__”的签名与超类型“tuple”不兼容 - 但 __sub__

如何解决mypy:“__add__”的签名与超类型“tuple”不兼容 - 但 __sub__

我正在制作一个简单的向量类,我正在努力理解 mypy 如何处理我的 __add____sub__ 方法(特别是代码 1 与代码中 mypy 输出的差异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 不同?

非常感谢。

编辑

我猜答案是因为超类 NamedTuple 允许加法,但指定第二个参数是类型 object代码 2 允许,而代码 1 不允许。

代码 3 可以找到 mypy,因为 NamedTuple 没有实现 __sub__

解决方法

Liskov substitution principle (LSP) 声明子类型的对象应始终可用以代替超类型的对象。在这种情况下,超类型是 tuple,它有一个 __add__ 方法接受另一个 tuple

在您的代码 #1 中,您覆盖了此 __add__ 方法,但您覆盖的方法不能代替原始方法,因为它只接受 Vector,而不接受任意 {{1} }.所以这违反了 LSP,因此它是一个类型错误。

您的代码 #2 没有错误,因为您重写的 tuple 方法接受任何 __add__,因此原始方法的任何有效参数也是新方法的有效参数。这意味着可以使用子类型代替超类型,因此不会违反 LSP。

您的代码 #3 没有错误,因为您的 object 方法没有覆盖超类型中的任何方法 - 未定义 __sub__ 的减法 - 并且添加新方法不会违反 LSP因为当使用对象代替超类型时,这个新方法根本不会被调用。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。