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

Nic*_*ing 9 python types typechecking python-3.x mypy

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

我有一些更复杂的代码,我已经减少到重现错误所需的最简单的python类:

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

    def __eq__(self, other: MyObject) -> bool:
        return self.value == other.value
Run Code Online (Sandbox Code Playgroud)

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

test.py: note: In class "MyObject":
test.py:5: error: Argument 1 of "__eq__" incompatible with supertype "object"
Run Code Online (Sandbox Code Playgroud)

我的基础上的理论,这些文档__eq____ne__对象上已经定义的类型,这是与这些类型的我子类的重新定义冲突.我的问题是如何定义这些类型以确保__eq__使用我选择的类型进行类型检查.

use*_*ica 7

==应该采取任意其他对象,而不仅仅是你的类型的对象.如果它无法识别其他对象,则应返回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
Run Code Online (Sandbox Code Playgroud)

此外,如果您需要MyObject在自己的正文中引用类型提示,则需要使用字符串,'MyObject'而不是MyObject.MyObject还不存在.


Gre*_*ice 5

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

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

您可以做的就是在方法主体的前面检查类型并返回(或引发异常):

if not isinstance(other, MyObject):
  return False
Run Code Online (Sandbox Code Playgroud)

然后,正如这些文档所说,Mypy 足够聪明,在检查之后,它会知道这other是 aMyObject并相应地对待它。