为什么定义 __eq__ 的参数类型会引发 MyPy 类型错误?

Why does defining the argument types for __eq__ throw a MyPy type error?

我正在使用 Python 3.5.1 和新发布的 MyPy v0.4.1 静态类型分析器。

我有一些更复杂的代码,我已将其简化为最简单的代码 python class 需要重现错误:

class MyObject(object):
    def __init__(self, value: int=5) -> None:
        self.value = value

    def __eq__(self, other: MyObject) -> bool:
        return self.value == other.value

运行 类型检查器 mypy test.py 产生以下错误:

test.py: note: In class "MyObject":
test.py:5: error: Argument 1 of "__eq__" incompatible with supertype "object"

我基于 these docs 的理论是对象上的 __eq____ne__ 已经定义了类型,这与我的子class 对这些的重新定义相冲突类型。我的问题是如何定义这些类型以确保 __eq__ 是用我选择的类型进行类型检查的。

== 应该接受任意其他对象,而不仅仅是您类型的对象。如果它不能识别另一个对象,它应该 return NotImplemented:

class MyObject(object):
    def __init__(self, value: int=5) -> None:
        self.value = value

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, MyObject):
            return NotImplemented
        return self.value == other.value

NotImplemented 不是 bool 的实例,但 mypy 似乎有一个奇怪的特例。它希望 return 注释为 bool,并且不会抱怨 return NotImplemented 行。

此外,如果您需要参考 MyObject 以获取其自身内部的类型提示,则需要使用字符串 'MyObject' 而不是 MyObjectMyObject 还不存在。

您对文档的阅读是正确的——您需要为方法 (__eq__) 提供与基础 class (object) 中已有的相同的签名,或者更宽松的。

原因是因为您的 MyObjectobject 的子类型,所以 MyObject 可以传递到任何需要 object... 的地方意味着该代码可以将它与任何其他 object 进行比较,并且类型检查器没有合法的方式来抱怨。因此,为了反映这一点,您的 __eq__ 必须写成期望任何 object.

你可以做的是在方法主体的前面,检查类型和return(或引发异常):

if not isinstance(other, MyObject):
  return False

然后作为 those docs say,Mypy 足够聪明,在检查之后,它会知道 other 是一个 MyObject 并相应地对待它。

只有在没有继承的情况下,使用“isinstance()”的测试才有效,如果有,您需要覆盖派生的 类 中的 eq 或使用 if type (自我)!=类型(其他)