jr6*_*6tp 7 python python-3.x mypy
这是我的代码:
class Person:
def __init__(self, id):
self.id = id
def __eq__(self, other: 'Person') -> bool:
return self.id == other.id
def compare(self, other: 'Person') -> bool:
return self.id == other.id
Run Code Online (Sandbox Code Playgroud)
mypy 扔error: Argument 1 of "__eq__" incompatible with supertype "object"。
但是如果我删除__eq__方法,mypy 不会抱怨它虽然compare与 相同__eq__,我该怎么办?
根本问题是该__eq__方法应该接受任何对象:my_object == 3在运行时做是合法的,并且应该总是返回 False。您可以通过检查object Typeshed 中的基线类型定义来亲眼看到这一点: 的签名__eq__为def __eq__(self, o: object) -> bool: ...
因此,为了完成这项工作,正确的实施方法是执行__eq__以下操作:
def __eq__(self, other: object) -> bool:
if not isinstance(other, Person):
# If we return NotImplemented, Python will automatically try
# running other.__eq__(self), in case 'other' knows what to do with
# Person objects.
return NotImplemented
return self.id == other.id
Run Code Online (Sandbox Code Playgroud)
事实上,如果您更新正在使用的 mypy 版本,它会打印出一条注释,建议您以这种方式构建代码。
但是,这种方法的问题在于,如果您执行诸如Person() == 3. 从技术上讲,这应该返回一个 bool,但从实用角度讲,如果您将 person 对象与 int 进行比较,您的代码可能存在错误。
值得庆幸的是,mypy 最近获得了一项可以标记此类错误的功能:--strict-equality. 现在,当您使用该标志运行 mypy 时,即使您以上述方式定义,这样做Person() == 3也会使 mypy 输出错误。Non-overlapping equality check (left operand type: "Person", right operand type: "int")__eq__
请注意,在下一个版本的 mypy (0.680) 发布之前,您需要使用 master 中最新版本的 mypy 才能使用此标志。在撰写本文时,这应该会在大约 2 到 3 周内发生。
如果__eq__无论出于何种原因,您都无法以上述方式定义,我个人建议抑制类型错误,而不是将 Person 替换为Any。
所以基本上,这样做:
def __eq__(self, other: 'Person') -> bool: # type: ignore
return self.id == other.id
Run Code Online (Sandbox Code Playgroud)
...也许还有一个关于你为什么要抑制错误的简短说明。
这里的基本原理是__eq__严格来说这个定义是不安全的(它违反了所谓的 Liskov 替换原则)——如果你需要做一些不安全的事情,最好明确标记你正在颠覆类型系统而不是使用 Any 隐藏它。
至少这样,您仍然可以使表达式像Person() == 3类型错误一样——如果您使用Any,像这样的表达式Person() == 3将默默地进行类型检查。在这一点上,您还不如使用object和构建您的代码以使其行为正确。