Python,我应该基于__eq__实现__ne __()操作员吗?
-
08-10-2019 - |
题
我有一堂课,我想覆盖 __eq__()
操作员。我应该覆盖 __ne__()
运营商也是如此,但是实施是否有意义 __ne__
基于 __eq__
像这样?
class A:
def __eq__(self, other):
return self.value == other.value
def __ne__(self, other):
return not self.__eq__(other)
还是Python使用这些操作员的方式我会缺少某些东西,这使这不是一个好主意?
解决方案
是的,这很好。实际上, 文档 敦促您定义 __ne__
定义时 __eq__
:
比较操作员之间没有隐含的关系。真理
x==y
并不意味着x!=y
是错误的。因此,定义__eq__()
, ,也应该定义__ne__()
这样运营商将按预期行事。
在许多情况下(例如这种情况),这将与否定结果一样简单 __eq__
, , 但不总是。
其他提示
python,我应该实施
__ne__()
基于操作员__eq__
?
简短答案:否。使用 ==
而不是 __eq__
在Python 3中, !=
是否定的 ==
默认情况下,因此您甚至不需要编写 __ne__
, ,并且文档不再在写一篇文章上。
一般而言,对于仅python的3-限制代码,除非您需要掩盖父的实现,否则请不要编写一个代码,例如内置对象。
也就是说,请记住 雷蒙德·赫廷格(Raymond Hettinger)的评论:
这
__ne__
方法自动遵循__eq__
除非__ne__
尚未在超级类中定义。因此,如果您是从内置的,最好覆盖两者。
如果您需要在Python 2中工作的代码,请遵循Python 2的建议,它将在Python 3中使用。
在Python 2中,Python本身不会自动以其他操作实施任何操作 - 因此,您应定义 __ne__
按照 ==
而不是 __eq__
。例如
class A(object):
def __eq__(self, other):
return self.value == other.value
def __ne__(self, other):
return not self == other # NOT `return not self.__eq__(other)`
请参阅证明
- 实施
__ne__()
基于操作员__eq__
和 - 不实施
__ne__
在Python 2中
在下面的演示中提供了不正确的行为。
长答案
这 文档 对于Python 2说:
比较操作员之间没有隐含的关系。真理
x==y
并不意味着x!=y
是错误的。因此,定义__eq__()
, ,也应该定义__ne__()
这样运营商将按预期行事。
因此,这意味着如果我们定义 __ne__
以 __eq__
, ,我们可以获得一致的行为。
该文档的这一部分已更新 Python 3:
默认,
__ne__()
代表__eq__()
并反转结果,除非是NotImplemented
.
在 “新功能”部分, ,我们看到这种行为发生了变化:
!=
现在返回相反的==
, , 除非==
返回NotImplemented
.
用于实施 __ne__
, ,我们更喜欢使用 ==
操作员 而不是使用 __eq__
直接的方法,如果 self.__eq__(other)
子类退货 NotImplemented
对于已检查的类型,Python将适当检查 other.__eq__(self)
从文档:
这 NotImplemented
目的
这种类型具有单个值。有一个具有此值的对象。通过内置名称访问此对象
NotImplemented
. 。如果数字方法和丰富的比较方法未实施所提供操作数的操作,则可以返回此值。 (然后,解释器将根据操作员尝试反射的操作或其他一些后备。)其真实价值是正确的。
当给予丰富的比较操作员时,如果他们的类型不是相同的类型,则python检查是否存在 other
是亚型,如果已定义了该操作员,则使用 other
首先的方法(逆 <
, <=
, >=
和 >
)。如果 NotImplemented
退还, 然后 它使用相反的方法。 (确实如此 不是 两次检查相同的方法。)使用 ==
操作员允许进行此逻辑。
期望
从语义上讲,您应该实施 __ne__
就检查平等的检查而言,因为您的班级用户将期望以下功能在所有情况下等效。
def negation_of_equals(inst1, inst2):
"""always should return same as not_equals(inst1, inst2)"""
return not inst1 == inst2
def not_equals(inst1, inst2):
"""always should return same as negation_of_equals(inst1, inst2)"""
return inst1 != inst2
也就是说,以上两个功能都应 总是 返回相同的结果。但这取决于程序员。
定义意外行为的演示 __ne__
基于 __eq__
:
首先设置:
class BaseEquatable(object):
def __init__(self, x):
self.x = x
def __eq__(self, other):
return isinstance(other, BaseEquatable) and self.x == other.x
class ComparableWrong(BaseEquatable):
def __ne__(self, other):
return not self.__eq__(other)
class ComparableRight(BaseEquatable):
def __ne__(self, other):
return not self == other
class EqMixin(object):
def __eq__(self, other):
"""override Base __eq__ & bounce to other for __eq__, e.g.
if issubclass(type(self), type(other)): # True in this example
"""
return NotImplemented
class ChildComparableWrong(EqMixin, ComparableWrong):
"""__ne__ the wrong way (__eq__ directly)"""
class ChildComparableRight(EqMixin, ComparableRight):
"""__ne__ the right way (uses ==)"""
class ChildComparablePy3(EqMixin, BaseEquatable):
"""No __ne__, only right in Python 3."""
实例化非等效实例:
right1, right2 = ComparableRight(1), ChildComparableRight(2)
wrong1, wrong2 = ComparableWrong(1), ChildComparableWrong(2)
right_py3_1, right_py3_2 = BaseEquatable(1), ChildComparablePy3(2)
预期行为:
(注意:虽然下面的每一秒钟都等效,因此在逻辑上是逻辑上的,但我包括它们以证明他们 当一个是另一个子类时,订单无关紧要。)
这些实例有 __ne__
实施 ==
:
assert not right1 == right2
assert not right2 == right1
assert right1 != right2
assert right2 != right1
这些实例(根据Python 3进行的测试)也可以正常工作:
assert not right_py3_1 == right_py3_2
assert not right_py3_2 == right_py3_1
assert right_py3_1 != right_py3_2
assert right_py3_2 != right_py3_1
并回想一下这些 __ne__
实施 __eq__
- 虽然这是预期的行为,但实施是不正确的:
assert not wrong1 == wrong2 # These are contradicted by the
assert not wrong2 == wrong1 # below unexpected behavior!
意外行为:
请注意,此比较与上述比较相矛盾(not wrong1 == wrong2
).
>>> assert wrong1 != wrong2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError
和,
>>> assert wrong2 != wrong1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError
不要跳过 __ne__
在Python 2中
为了证明您不应该跳过实施 __ne__
在Python 2中,请参见以下等效对象:
>>> right_py3_1, right_py3_1child = BaseEquatable(1), ChildComparablePy3(1)
>>> right_py3_1 != right_py3_1child # as evaluated in Python 2!
True
以上结果应该是 False
!
Python 3来源
默认的CPYTHON实现 __ne__
在 typeobject.c
在 object_richcompare
:
case Py_NE:
/* By default, __ne__() delegates to __eq__() and inverts the result,
unless the latter returns NotImplemented. */
if (self->ob_type->tp_richcompare == NULL) {
res = Py_NotImplemented;
Py_INCREF(res);
break;
}
res = (*self->ob_type->tp_richcompare)(self, other, Py_EQ);
if (res != NULL && res != Py_NotImplemented) {
int ok = PyObject_IsTrue(res);
Py_DECREF(res);
if (ok < 0)
res = NULL;
else {
if (ok)
res = Py_False;
else
res = Py_True;
Py_INCREF(res);
}
}
我们在这里看到
但是默认值 __ne__
用途 __eq__
?
Python 3的默认值 __ne__
C级的实现细节使用 __eq__
因为更高的级别 ==
(pyobject_richcompare)效率较低 - 因此,它也必须处理 NotImplemented
.
如果 __eq__
正确实施,然后否定 ==
也是正确的 - 它使我们能够避免在我们的 __ne__
.
使用 ==
允许我们保持低级逻辑 一 地点,然后 避免 寻址 NotImplemented
在 __ne__
.
一个人可能会错误地假设 ==
可以返回 NotImplemented
.
它实际上使用与默认实现相同的逻辑 __eq__
, ,检查身份(请参阅 do_richcompare 和我们下面的证据)
class Foo:
def __ne__(self, other):
return NotImplemented
__eq__ = __ne__
f = Foo()
f2 = Foo()
和比较:
>>> f == f
True
>>> f != f
False
>>> f2 == f
False
>>> f2 != f
True
表现
不要相信我的话,让我们看看表现更多的人:
class CLevel:
"Use default logic programmed in C"
class HighLevelPython:
def __ne__(self, other):
return not self == other
class LowLevelPython:
def __ne__(self, other):
equal = self.__eq__(other)
if equal is NotImplemented:
return NotImplemented
return not equal
def c_level():
cl = CLevel()
return lambda: cl != cl
def high_level_python():
hlp = HighLevelPython()
return lambda: hlp != hlp
def low_level_python():
llp = LowLevelPython()
return lambda: llp != llp
我认为这些表演数字不言而喻:
>>> import timeit
>>> min(timeit.repeat(c_level()))
0.09377292497083545
>>> min(timeit.repeat(high_level_python()))
0.2654011140111834
>>> min(timeit.repeat(low_level_python()))
0.3378178110579029
当您考虑到 low_level_python
在Python中进行逻辑,否则将在C级别上处理。
对某些批评家的回应
另一个答案者写道:
亚伦·霍尔的实施
not self == other
的__ne__
方法是不正确的,因为它永远无法返回NotImplemented
(not NotImplemented
是False
),因此__ne__
优先级的方法永远不会退缩__ne__
没有优先级的方法。
有 __ne__
永远不会回来 NotImplemented
不会使它不正确。相反,我们处理优先级 NotImplemented
通过检查平等的检查 ==
. 。假设 ==
正确实施,我们完成了。
not self == other
曾经是默认的Python 3实现__ne__
方法但这是一个错误,如Shadowranger所注意到的,2015年1月在Python 3.4中进行了纠正(请参阅第21408期)。
好吧,让我们解释一下。
如前所述,默认情况下Python 3 __ne__
首先检查是否 self.__eq__(other)
返回 NotImplemented
(单身人士) - 应该检查 is
并返回如果是这样,否则应返回倒数。这是将逻辑写成类Mixin的逻辑:
class CStyle__ne__:
"""Mixin that provides __ne__ functionality equivalent to
the builtin functionality
"""
def __ne__(self, other):
equal = self.__eq__(other)
if equal is NotImplemented:
return NotImplemented
return not equal
这对于C级Python API的正确性是必不可少的,并且在Python 3中引入
多余的。所有相关 __ne__
删除了方法,包括实施自己的检查以及委派的检查 __eq__
直接或通过 ==
- 和 ==
是最常见的方法。
结论
对于Python 2兼容代码,请使用 ==
实施 __ne__
. 。更多:
- 正确的
- 简单的
- 表演者
仅在Python 3中,使用C级别的低级否定 - 甚至是 更多的 简单且性能(尽管程序员负责确定它是 正确的).
再次,做 不是 在高级Python中写下低级逻辑。
只是为了记录,一个规范上正确的py2/py3便携式 __ne__
看起来像:
import sys
class ...:
...
def __eq__(self, other):
...
if sys.version_info[0] == 2:
def __ne__(self, other):
equal = self.__eq__(other)
return equal if equal is NotImplemented else not equal
这可以与任何 __eq__
您可能会定义:
- 与众不同
not (self == other)
, ,在某些令人讨厌/复杂的情况下不会干扰涉及比较的烦人/复杂案例,其中涉及的一个班级并不意味着__ne__
与结果相同not
上__eq__
(例如Sqlalchemy's Orm,两者都__eq__
和__ne__
返回特殊代理对象,而不是True
或者False
, ,并试图not
的结果__eq__
会返回False
, ,而不是正确的代理对象)。 - 与众不同
not self.__eq__(other)
, ,正确地委派了__ne__
另一个实例self.__eq__
返回NotImplemented
(not self.__eq__(other)
会额外错,因为NotImplemented
是真实的,所以__eq__
不知道如何进行比较,__ne__
会返回False
, ,这意味着两个对象实际上是平等的,而实际上唯一的对象不知道,这意味着默认值不等于)
如果你的 __eq__
不使用 NotImplemented
返回,这起作用(无意义的开销),如果确实使用 NotImplemented
有时,这会正确处理。 Python版本检查意味着如果课程为 import
-Ed在Python 3中, __ne__
不确定,允许Python的本地,有效的后备 __ne__
实现(上述C版本) 接管。
为什么需要
Python超载规则
为什么您这样做而不是其他解决方案的解释有些无法触及。 Python有一些有关超载运营商的一般规则,尤其是比较操作员:
- (适用于所有操作员)运行时
LHS OP RHS
, , 尝试LHS.__op__(RHS)
, ,如果那回来NotImplemented
, , 尝试RHS.__rop__(LHS)
. 。例外:如果RHS
是LHS
的课,然后测试RHS.__rop__(LHS)
第一的. 。在比较操作员的情况下__eq__
和__ne__
是他们自己的“ rop”(所以测试顺序__ne__
是LHS.__ne__(RHS)
, , 然后RHS.__ne__(LHS)
, ,如果是反转RHS
是LHS
的课) - 除了“交换”操作员的想法之外,操作员之间没有隐含的关系。即使例如同一类,
LHS.__eq__(RHS)
返回True
不暗示LHS.__ne__(RHS)
返回False
(实际上,操作员甚至不需要返回布尔值;像sqlalchemy这样的Orms无意地不返回,允许更具表现力的查询语法)。截至Python 3,默认值__ne__
实施方式是这种方式,但这不是合同;您可以覆盖__ne__
以不严格的对立的方式__eq__
.
这如何适用于超载比较器
因此,当您超载操作员时,您有两个工作:
- 如果您知道如何自己实施操作,请使用 只要 您对如何进行比较的了解(切勿隐式或明确地委派到操作的另一侧;这样做的风险不正确和/或无限递归,具体取决于您的工作方式)
- 如果你 别 知道如何自己实施操作, 总是 返回
NotImplemented
, ,因此Python可以将其委派给其他操作数的实现
问题 not self.__eq__(other)
def __ne__(self, other):
return not self.__eq__(other)
切勿委派另一侧(如果 __eq__
正确返回 NotImplemented
)。什么时候 self.__eq__(other)
返回 NotImplemented
(这是“真实的”),您默默地回来 False
, , 所以 A() != something_A_knows_nothing_about
返回 False
, ,什么时候应该检查 something_A_knows_nothing_about
知道如何与 A
, ,如果没有,它应该返回 True
(由于双方都不知道如何与对方进行比较,因此它们被认为不等)。如果 A.__eq__
未正确实施(返回 False
代替 NotImplemented
当它不识别对方时),这是从 A
的观点,回归 True
(自从 A
不认为它是平等的,所以它不是平等的),但是可能是错误的 something_A_knows_nothing_about
的观点,因为它甚至从未问过 something_A_knows_nothing_about
; A() != something_A_knows_nothing_about
结局 True
, , 但 something_A_knows_nothing_about != A()
可以 False
, ,或任何其他返回值。
问题 not self == other
def __ne__(self, other):
return not self == other
更微妙。 99%的课程将是正确的,包括所有课程 __ne__
是逻辑逆的 __eq__
. 。但 not self == other
违反上面提到的两个规则,这意味着对于课堂 __ne__
不是 逻辑倒数 __eq__
, ,结果再次是非反射性的,因为从未询问其中一个操作数可以实现 __ne__
完全,即使其他操作数不能。最简单的示例是返回的怪异类 False
为了 全部 比较,所以 A() == Incomparable()
和 A() != Incomparable()
两者都返回 False
. 。正确实现 A.__ne__
(一个返回 NotImplemented
当它不知道如何进行比较),这种关系是反身的。 A() != Incomparable()
和 Incomparable() != A()
同意结果(因为在前一种情况下, A.__ne__
返回 NotImplemented
, , 然后 Incomparable.__ne__
返回 False
, ,在后者时, Incomparable.__ne__
返回 False
直接地)。但当 A.__ne__
被实施为 return not self == other
, A() != Incomparable()
返回 True
(因为 A.__eq__
返回,不是 NotImplemented
, , 然后 Incomparable.__eq__
返回 False
, , 和 A.__ne__
将其倒转 True
), 尽管 Incomparable() != A()
返回 False.
您可以看到一个示例 这里.
显然,一个总是返回的课程 False
对彼此而言 __eq__
和 __ne__
有点奇怪。但是如前所述, __eq__
和 __ne__
甚至不需要返回 True
/False
; Sqlalchemy Orm的课程带有比较器,可返回一个特殊的代理对象,而不是 True
/False
根本(如果在布尔语境中进行评估,它们是“真实的”,但绝不应该在这种情况下进行评估)。
通过无法超载 __ne__
正确,你 将要 分类的类别,作为代码:
results = session.query(MyTable).filter(MyTable.fieldname != MyClassWithBadNE())
会起作用(假设Sqlalchemy知道如何插入 MyClassWithBadNE
完全进入SQL字符串;这可以使用类型适配器无需 MyClassWithBadNE
完全必须合作),将预期的代理对象传递给 filter
, , 尽管:
results = session.query(MyTable).filter(MyClassWithBadNE() != MyTable.fieldname)
最终会通过 filter
平原 False
, , 因为 self == other
返回代理对象,并 not self == other
只是将真相的代理对象转换为 False
. 。希望, filter
对处理无效论据的抛出例外 False
. 。虽然我敢肯定很多人会争辩 MyTable.fieldname
应该 在比较的左侧保持一致,事实仍然是没有程序化的理由在一般情况下执行此操作,也没有正确的通用通用 __ne__
无论哪种方式都可以工作 return not self == other
仅在一个安排中工作。
简短答案:是的(但请阅读文档以正确执行)
Shadowranger的实施 __ne__
方法是正确的(从某种意义上说,它的行为与默认的Python 3实现完全一样):
def __ne__(self, other):
result = self.__eq__(other)
if result is not NotImplemented:
return not result
return NotImplemented
亚伦·霍尔的实施 not self == other
的 __ne__
方法是不正确的,因为它永远无法返回 NotImplemented
(not NotImplemented
是 False
),因此 __ne__
优先级的方法永远不会退缩 __ne__
没有优先级的方法。 not self == other
曾经是默认的Python 3实现 __ne__
方法但这是一个错误,正如Shadowranger所注意到的,2015年1月在Python 3.4中进行了纠正(请参阅 问题#21408).
比较操作员的实施
这 Python语言参考 对于Python 3个州 第三章数据模型:
object.__lt__(self, other)
object.__le__(self, other)
object.__eq__(self, other)
object.__ne__(self, other)
object.__gt__(self, other)
object.__ge__(self, other)
这些是所谓的“丰富比较”方法。操作员符号和方法名称之间的对应关系如下:
x<y
呼叫x.__lt__(y)
,x<=y
呼叫x.__le__(y)
,x==y
呼叫x.__eq__(y)
,x!=y
呼叫x.__ne__(y)
,x>y
呼叫x.__gt__(y)
, , 和x>=y
呼叫x.__ge__(y)
.丰富的比较方法可能会返回单例
NotImplemented
如果它不为给定的参数实施操作。这些方法没有交换的题词版本(当左参数不支持操作时使用,但正确的参数确实可以使用);相当,
__lt__()
和__gt__()
是彼此的反思,__le__()
和__ge__()
是彼此的反思,并且__eq__()
和__ne__()
是他们自己的反思。如果操作数具有不同的类型,而右操作数的类型是左操作数类型的直接或间接子类,则右操作数的反射方法优先,否则左操作数的方法优先。不考虑虚拟子分类。
将其转换为Python代码提供(使用 operator_eq
为了 ==
, operator_ne
为了 !=
, operator_lt
为了 <
, operator_gt
为了 >
, operator_le
为了 <=
和 operator_ge
为了 >=
):
def operator_eq(left, right):
if type(left) != type(right) and isinstance(right, type(left)):
result = right.__eq__(left)
if result is NotImplemented:
result = left.__eq__(right)
else:
result = left.__eq__(right)
if result is NotImplemented:
result = right.__eq__(left)
if result is NotImplemented:
result = left is right
return result
def operator_ne(left, right):
if type(left) != type(right) and isinstance(right, type(left)):
result = right.__ne__(left)
if result is NotImplemented:
result = left.__ne__(right)
else:
result = left.__ne__(right)
if result is NotImplemented:
result = right.__ne__(left)
if result is NotImplemented:
result = left is not right
return result
def operator_lt(left, right):
if type(left) != type(right) and isinstance(right, type(left)):
result = right.__gt__(left)
if result is NotImplemented:
result = left.__lt__(right)
else:
result = left.__lt__(right)
if result is NotImplemented:
result = right.__gt__(left)
if result is NotImplemented:
raise TypeError(f"'<' not supported between instances of '{type(left).__name__}' and '{type(right).__name__}'")
return result
def operator_gt(left, right):
if type(left) != type(right) and isinstance(right, type(left)):
result = right.__lt__(left)
if result is NotImplemented:
result = left.__gt__(right)
else:
result = left.__gt__(right)
if result is NotImplemented:
result = right.__lt__(left)
if result is NotImplemented:
raise TypeError(f"'>' not supported between instances of '{type(left).__name__}' and '{type(right).__name__}'")
return result
def operator_le(left, right):
if type(left) != type(right) and isinstance(right, type(left)):
result = right.__ge__(left)
if result is NotImplemented:
result = left.__le__(right)
else:
result = left.__le__(right)
if result is NotImplemented:
result = right.__ge__(left)
if result is NotImplemented:
raise TypeError(f"'<=' not supported between instances of '{type(left).__name__}' and '{type(right).__name__}'")
return result
def operator_ge(left, right):
if type(left) != type(right) and isinstance(right, type(left)):
result = right.__le__(left)
if result is NotImplemented:
result = left.__ge__(right)
else:
result = left.__ge__(right)
if result is NotImplemented:
result = right.__le__(left)
if result is NotImplemented:
raise TypeError(f"'>=' not supported between instances of '{type(left).__name__}' and '{type(right).__name__}'")
return result
比较方法的默认实现
该文档补充说:
默认,
__ne__()
代表__eq__()
并反转结果,除非是NotImplemented
. 。比较操作员之间没有其他隐含关系,例如(x<y or x==y)
不暗示x<=y
.
比较方法的默认实现(__eq__
, __ne__
, __lt__
, __gt__
, __le__
和 __ge__
)因此可以通过:
def __eq__(self, other):
return NotImplemented
def __ne__(self, other):
result = self.__eq__(other)
if result is not NotImplemented:
return not result
return NotImplemented
def __lt__(self, other):
return NotImplemented
def __gt__(self, other):
return NotImplemented
def __le__(self, other):
return NotImplemented
def __ge__(self, other):
return NotImplemented
因此,这是正确的实施 __ne__
方法。而且它并不总是返回 __eq__
方法是因为当 __eq__
方法返回 NotImplemented
, ,它的倒数 not NotImplemented
是 False
(作为 bool(NotImplemented)
是 True
)而不是所需的 NotImplemented
.
错误的实现 __ne__
正如亚伦·霍尔(Aaron Hall)所展示的那样, not self.__eq__(other)
不是默认实现的 __ne__
方法。 但是也不是 not self == other
. 下面通过将默认实现的行为与行为进行比较,证明了后者 not self == other
在两种情况下实施:
- 这
__eq__
方法返回NotImplemented
; - 这
__eq__
方法返回一个不同的值NotImplemented
.
默认实现
让我们看看当 A.__ne__
方法使用默认实现和 A.__eq__
方法返回 NotImplemented
:
class A:
pass
class B:
def __ne__(self, other):
return "B.__ne__"
assert (A() != B()) == "B.__ne__"
!=
呼叫A.__ne__
.A.__ne__
呼叫A.__eq__
.A.__eq__
返回NotImplemented
.!=
呼叫B.__ne__
.B.__ne__
返回"B.__ne__"
.
这表明当 A.__eq__
方法返回 NotImplemented
, , 这 A.__ne__
方法落在 B.__ne__
方法。
现在让我们看看当 A.__ne__
方法使用默认实现和 A.__eq__
方法返回一个不同的值 NotImplemented
:
class A:
def __eq__(self, other):
return True
class B:
def __ne__(self, other):
return "B.__ne__"
assert (A() != B()) is False
!=
呼叫A.__ne__
.A.__ne__
呼叫A.__eq__
.A.__eq__
返回True
.!=
返回not True
, , 那是False
.
这表明在这种情况下, A.__ne__
方法返回 A.__eq__
方法。就这样 __ne__
方法的表现为文档中广告宣传的方法。
覆盖默认实现的 A.__ne__
具有上述正确实现的方法得出相同的结果。
not self == other
执行
让我们看看覆盖默认实现的情况会发生什么 A.__ne__
方法 not self == other
实施和 A.__eq__
方法返回 NotImplemented
:
class A:
def __ne__(self, other):
return not self == other
class B:
def __ne__(self, other):
return "B.__ne__"
assert (A() != B()) is True
!=
呼叫A.__ne__
.A.__ne__
呼叫==
.==
呼叫A.__eq__
.A.__eq__
返回NotImplemented
.==
呼叫B.__eq__
.B.__eq__
返回NotImplemented
.==
返回A() is B()
, , 那是False
.A.__ne__
返回not False
, , 那是True
.
默认实现的 __ne__
返回的方法 "B.__ne__"
, , 不是 True
.
现在让我们看看覆盖默认实现的情况会发生什么 A.__ne__
方法 not self == other
实施和 A.__eq__
方法返回一个不同的值 NotImplemented
:
class A:
def __eq__(self, other):
return True
def __ne__(self, other):
return not self == other
class B:
def __ne__(self, other):
return "B.__ne__"
assert (A() != B()) is False
!=
呼叫A.__ne__
.A.__ne__
呼叫==
.==
呼叫A.__eq__
.A.__eq__
返回True
.A.__ne__
返回not True
, , 那是False
.
默认实现的 __ne__
方法还返回 False
在这种情况下。
由于此实现未能复制默认实现的行为 __ne__
方法时 __eq__
方法返回 NotImplemented
, ,这是不正确的。
如果全部 __eq__
, __ne__
, __lt__
, __ge__
, __le__
, , 和 __gt__
对班级有意义,然后实施 __cmp__
反而。否则,像您一样做,因为丹尼尔·迪波洛(Daniel Dipaolo)说的一点(当我在测试它而不是查找;))