我正在使用 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__
使用我选择的类型进行类型检查。
==
应该接受任意其他对象,而不仅仅是您类型的对象。如果它不能识别另一个对象,它应该返回 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
尚不存在。
您对文档的阅读是正确的——您需要为方法 (
__eq__
) 提供与基类 (object
) 中已有的相同签名,或者更宽松的签名。
这样做的原因是,因为您的
MyObject
是 object
的子类型,所以 MyObject
可以传递到任何需要 object
的地方...这意味着该代码可以将其与任何其他 object
进行比较
,并且类型检查器没有合法的方式来抱怨。因此,为了反映这一点,您的 __eq__
必须写入以期待任何 object
。
您可以做的就是在方法主体的前面,检查类型并返回(或引发异常):
if not isinstance(other, MyObject):
return False
然后正如那些文档所说,Mypy 足够聪明,在检查之后,它会知道
other
是 MyObject
并相应地对待它。
我将使用
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
使用“isinstance()”的测试仅在没有继承的情况下才有效,如果有继承,您要么需要在派生类中重写 eq 要么使用 if type(self) != type(other)