mypy:“__ eq__”与超类型“对象”不兼容

问题描述 投票:2回答:1

这是我的代码:

class Person:
    def __init__(self, id):
        self.id = id

    def __eq__(self, other: 'Person') -> bool:
        return self.id == other.id

   def compare(self, other: 'Person') -> bool:
        return self.id == other.id

mypy throw error: Argument 1 of "__eq__" incompatible with supertype "object"

但是,如果我删除__eq__方法,mypy不会抱怨它虽然compare__eq__相同,我该怎么办?

python python-3.x mypy
1个回答
4
投票

根本问题是__eq__方法应该接受任何对象:在运行时执行my_object == 3是合法的,并且应该总是返回False。您可以通过检查object in Typeshed的基线类型定义来自行查看:__eq__的签名为def __eq__(self, o: object) -> bool: ...

因此,为了使这项工作,实现__eq__的正确方法是执行以下操作:

def __eq__(self, other: object) -> bool:
    if not isinstance(other, Person):
        # If we return NotImplemented, Python will automatically try
        # running other.__eq__(self), in case 'other' knows what to do with
        # Person objects.
        return NotImplemented
    return self.id == other.id

事实上,如果你更新你正在使用的mypy版本,它会打印出一条注释,建议你以这种方式构建你的代码。

然而,这种方法的问题是,如果你做像Person() == 3这样愚蠢的事情,mypy现在不再抱怨了。从技术上讲,这应该返回一个bool,但实际上,如果你将一个person对象与一个int进行比较,你的代码可能会有一个bug。

值得庆幸的是,mypy最近获得了一个可以标记这些错误的功能:--strict-equality。现在,当您使用该标志运行mypy时,即使您按照上述方式定义Person() == 3,执行Non-overlapping equality check (left operand type: "Person", right operand type: "int")也会使qpyxswpoi出现mypy输出错误。

请注意,您需要使用最新版本的mypy来使用此标志,直到mypy(0.680)的下一个版本发布。这应该在写作时间大约2至3周内发生。


如果以上述方式定义__eq__不是出于任何原因你可以做的事情,我个人建议抑制类型错误而不是用__eq__替换Person。

所以基本上,这样做:

Any

...也许还有一个简短的说明,说明你为什么要压制这个错误。

这里的基本原理是严格来说这个def __eq__(self, other: 'Person') -> bool: # type: ignore return self.id == other.id 的定义是不安全的(它违反了被称为Liskov替换原则的东西) - 如果你需要做一些不安全的事情,那么明确标记你是在颠覆类型系统可能更好然后使用Any隐藏它。

至少这样,你仍然可以使像__eq__这样的表达式成为类型错误 - 如果你使用Person() == 3,像Any这样的表达式会默默地进行类型检查。此时,您可以使用Person() == 3并构建代码以正确运行。

© www.soinside.com 2019 - 2024. All rights reserved.