为啥为 __eq__ 定义参数类型会引发 MyPy 类型错误?
Posted
技术标签:
【中文标题】为啥为 __eq__ 定义参数类型会引发 MyPy 类型错误?【英文标题】:Why does defining the argument types for __eq__ throw a MyPy type error?为什么为 __eq__ 定义参数类型会引发 MyPy 类型错误? 【发布时间】:2016-09-30 03:46:44 【问题描述】:我正在使用 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"
我基于these docs 的理论是对象上的__eq__
和__ne__
已经定义了类型,这与我的子类对这些类型的重新定义相冲突。我的问题是如何定义这些类型以确保 __eq__
使用我选择的类型进行类型检查。
【问题讨论】:
【参考方案1】:==
应该采用任意其他对象,而不仅仅是您类型的对象。如果它不能识别另一个对象,它应该返回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 似乎有一个奇怪的特殊情况。它希望返回注解为bool
,并且它不会抱怨return NotImplemented
行。
另外,如果您需要参考MyObject
以获取其自身内部的类型提示,则需要使用字符串'MyObject'
而不是MyObject
。 MyObject
还不存在。
【讨论】:
Re: 在它自己的正文中引用MyObject
,我已经在我的代码的其他地方没有引用,我没有从 MyPy 得到错误:github.com/pirate/py-data/blob/master/…
@NickSweeting:你跑了吗? You should get an error when you try to run it.
啊,谢谢@user2357112,我只尝试了 mypy-ing 并忽略了实际运行它。将其更改为字符串有效。
我刚刚意识到的一件事,我以前从未见过函数返回异常类型(而不是raise
ing 他们),这是标准做法吗?
@NickSweeting:NotImplemented 也不例外。您正在考虑 NotImplementedError。返回 NotImplemented 是您表示您的特殊方法没有为操作指定含义的方式,因此 Python 应该尝试其他对象的方法。我听说这是一个返回值,而不是出于速度目的的异常。【参考方案2】:
您对文档的阅读是正确的 - 您需要为方法 (__eq__
) 提供与基类 (object
) 中已有的签名相同的签名,或者更宽松的签名。
原因是因为您的MyObject
是object
的子类型,所以MyObject
可以传递到任何需要object
... 这意味着该代码可以将其与任何其他代码进行比较object
,并且类型检查器没有合法的投诉方式。因此,为了反映这一点,您的__eq__
必须写成期望任何object
。
你可以做的是在方法体的前面,检查类型并返回(或引发异常):
if not isinstance(other, MyObject):
return False
那么作为those docs say,Mypy 足够聪明,在检查之后,它会知道other
是MyObject
并相应地对待它。
【讨论】:
【参考方案3】:使用“isinstance()”的测试仅在没有继承的情况下才有效,如果有,您需要在派生类中覆盖 eq 或使用 if type(self) != type(other)
【讨论】:
以上是关于为啥为 __eq__ 定义参数类型会引发 MyPy 类型错误?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Python 文档说我在定义 __eq__ 时需要定义 __ne__?
为啥 `if None.__eq__("a")` 似乎评估为 True(但不完全)?