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

问题描述 投票:0回答:4

我正在使用 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

运行类型检查器

mypy test.py
会产生以下错误:

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

我基于这些文档的理论是,

.__eq__(...)
.__ne__(...)
上的
object
已经定义了参数类型,这与我的子类对这些类型的重新定义相冲突。我的问题是如何定义这些类型以确保
__eq__
使用我选择的类型进行类型检查。

python python-3.x types typechecking mypy
4个回答
19
投票

==
应该接受任意其他对象,而不仅仅是您类型的对象。如果它不能识别另一个对象,它应该返回
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 似乎有一个奇怪的特殊情况。它按原样接受此代码。

在 Python 3.10 及更高版本中,您可以使用

types.NotImplementedType
更明确地了解 NotImplemented 的可能性:

from types import NotImplementedType

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

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

此外,如果您需要在其自身内部引用

MyObject
来获取类型提示,则需要使用字符串
'MyObject'
而不是
MyObject
MyObject
尚不存在。


5
投票

您对文档的阅读是正确的——您需要为方法 (

__eq__
) 提供与基类 (
object
) 中已有的相同签名,或者更宽松的签名。

这样做的原因是,因为您的

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

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

if not isinstance(other, MyObject):
  return False

然后正如那些文档所说,Mypy 足够聪明,在检查之后,它会知道

other
MyObject
并相应地对待它。


0
投票

我将使用

other
来定义每个对象类型的行为,而不是键入
isinstance
对象。这还可以启用类型提示,因为它在下面的行中定义了
other
的类型,并且允许在处理各种类相等性时定义不同的行为

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

    def __eq__(self, other) -> bool:
        if isinstance(other, MyObject):
            return self.value == other.value
        elif isinstance(other, MyOtherObject):
            return self.value == other.other_value
        return false

-1
投票

使用“isinstance()”的测试仅在没有继承的情况下才有效,如果有继承,您要么需要在派生类中重写 eq 要么使用 if type(self) != type(other)

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