Python, should I implement __ne__() operator based on __eq__?
我有一个类要在其中重写
1 2 3 4 5 6 | class A: def __eq__(self, other): return self.value == other.value def __ne__(self, other): return not self.__eq__(other) |
或者,我对python使用这些运算符的方式是否有所遗漏,从而使这不是一个好主意?
Python, should I implement
__ne__() operator based on__eq__ ?Ok.
号简短回答:不,用
在python 3中,默认情况下,
一般来说,对于仅用于Python3的代码,除非需要覆盖父实现(例如对于内置对象),否则不要编写一个。好的。
也就是说,记住Raymond Hettinger的评论:好的。
The
__ne__ method follows automatically from__eq__ only if
__ne__ isn't already defined in a superclass. So, if you're
inheriting from a builtin, it's best to override both.Ok.
号
如果您需要您的代码在Python2中工作,请遵循针对Python2的建议,它将在Python3中正常工作。好的。
在python 2中,python本身不会根据另一个操作自动实现任何操作,因此,您应该根据
1 2 3 4 5 6 | 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)` |
看证据吧好的。
- 基于
__eq__ 和 - 根本不在python 2中实现
__ne__ 。
在下面的演示中提供错误的行为。好的。冗长的回答
python 2的文档说明:好的。
There are no implied relationships among the comparison operators. The
truth ofx==y does not imply thatx!=y is false. Accordingly, when
defining__eq__() , one should also define__ne__() so that the
operators will behave as expected.Ok.
号
这意味着,如果我们用
文档的这一部分已针对python 3进行了更新:好的。
By default,
__ne__() delegates to__eq__() and inverts the result
unless it isNotImplemented .Ok.
号
在"新增内容"部分,我们看到这种行为发生了变化:好的。
!= now returns the opposite of== , unless== returnsNotImplemented .
号
为了实现
此类型只有一个值。有一个具有此值的对象。通过内置名称访问此对象埃多克斯1〔17〕。数值方法和富比较方法可能返回如果不实现操作数的操作,则为该值提供。(然后,解释器将尝试反射操作,或者其他一些回退,取决于运算符。)其真值为真的。好的。blockquote></
当给定的比较运算符丰富,如果他们是不一样的类型检查,如果
other Python是一个亚型,如果它是一other 算子定义的,它使用的方法(逆的第一< ,<= ,>= 和> )。如果NotImplemented 是返回,然后它使用相反的方法。(它不检查两次相同的方法。== )使用逻辑运算符允许这一地点。期望
你应该semantically
__ne__ 条件,实现在平等的检查用户所期望的,因为你想下面的函数类是等价的所有实例。
1
2
3
4
5
6
7 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__ 第一个安装程序:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 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."""instantiate非等价的实例:
1
2
3 right1, right2 = ComparableRight(1), ChildComparableRight(2)
wrong1, wrong2 = ComparableWrong(1), ChildComparableWrong(2)
right_py3_1, right_py3_2 = BaseEquatable(1), ChildComparablePy3(2)预期的行为:
(注:而第二断言每个下面是等价的,因此它是对一个在结尾,我包括他们证明,一阶不可的时候是一个其他收藏指正。)
论文实现的实例:一个
__ne__ ==
1
2
3
4 assert not right1 == right2
assert not right2 == right1
assert right1 != right2
assert right2 != right1论文在Python实例测试3,所以工作正确:
1
2
3
4 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__ while这是预期的行为,外部是不正确的:
1
2 assert not wrong1 == wrong2 # These are contradicted by the
assert not wrong2 == wrong1 # below unexpected behavior!意想不到的行为:
这是比较的比较contradicts级以上(
not wrong1 == wrong2 )。
1
2
3
4 >>> assert wrong1 != wrong2
Traceback (most recent call last):
File"<stdin>", line 1, in <module>
AssertionError和,
1
2
3
4 >>> assert wrong2 != wrong1
Traceback (most recent call last):
File"<stdin>", line 1, in <module>
AssertionError不要跳过
__ne__ Python 2你不应该跳过的证据是在Python实现
__ne__ 湖2,对象:命题等价
1
2
3 >>> 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
默认的实现是在
typeobject.c CPython的__ne__ 在object_richcompare :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 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__ 默认使用吗?3
__ne__ Python的默认实现细节层次的使用,因为在C__eq__ 高等级== (先不_ richcompare)是高效,因此它必须NotImplemented 所以手柄。如果是的话,
__eq__ 正确实施,学院== 否定是正确的-它允许美国以避免低层次的实现细节在我们的__ne__ 。
== 允许美国使用低层次的逻辑让我们在一个广场,在__ne__ NotImplemented 寻址和避免。一可能认为,
== NotImplemented 可能回报。它是使用相同的逻辑作为默认执行身份检查的
__eq__ (湖,这和我们做_ richcompare证据下面)
1
2
3
4
5
6
7 class Foo:
def __ne__(self, other):
return NotImplemented
__eq__ = __ne__
f = Foo()
f2 = Foo()和比较:
1
2
3
4
5
6
7
8 >>> f == f
True
>>> f != f
False
>>> f2 == f
False
>>> f2 != f
True性能
别相信我的话,让我们来看看什么更有效:好的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 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号
我认为这些业绩数字本身就说明了:好的。
1
2
3
4
5
6
7 >>> 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级别上处理。好的。对一些批评者的回应另一位回答者写道:好的。
Aaron Hall’s implementation
not self == other of the__ne__ method is incorrect as it can never returnNotImplemented (not NotImplemented isFalse ) and therefore the__ne__ method that has priority can never fall back on the__ne__ method that does not have priority.Ok.
号
让
__ne__ 永远不返回NotImplemented 并不意味着它是错误的。相反,我们通过检查与== 的相等性来处理与NotImplemented 的优先级。假设== 被正确执行,我们就完成了。好的。
not self == other used to be the default Python 3 implementation of the__ne__ method but it was a bug and it was corrected in Python 3.4 on January 2015, as ShadowRanger noticed (see issue #21408).Ok.
号
好吧,让我们解释一下。好的。
如前所述,默认情况下,python 3处理
__ne__ ,首先检查self.__eq__(other) 是否返回NotImplemented (单例),应使用is 检查并返回,否则应返回反向。下面是作为类混合编写的逻辑:好的。
1
2
3
4
5
6
7
8
9 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__ 方法关闭21408号问题,以及- 这里删除了后续清理中的
__ne__ 方法。冗余。删除了所有相关的
__ne__ 方法,包括实施自己检查的方法,以及直接或通过== 委托__eq__ 的方法,而== 是最常见的方法。好的。结论对于与python 2兼容的代码,使用
== 来实现__ne__ 。更重要的是:好的。
- 对的
- 简单的
- 性能
仅在Python3中,使用C级的低级否定——它更简单,性能更高(尽管程序员负责确定它是否正确)。好的。
同样,不要在高级Python中编写低级逻辑。好的。好啊。
是的,那很好。事实上,当您定义
__eq__ 时,文档敦促您定义__ne__ :There are no implied relationships
among the comparison operators. The
truth ofx==y does not imply thatx!=y
is false. Accordingly, when defining
__eq__() , one should also define__ne__() so that the operators will behave as expected.号
在很多情况下(比如这一个),它会像否定
__eq__ 的结果一样简单,但并不总是如此。就记录而言,一个标准正确的交叉PY2/PY3便携式
__ne__ 应该是:好的。
1
2
3
4
5
6
7
8
9
10
11 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__ 的结果与__eq__ 的not 的结果相同(如sqlAlchemy的ORM,其中__eq__ 和__ne__ 都返回特殊的代理对象,而不是__ne__ 返回特殊的代理对象。8]或False ,尝试not ,__eq__ 的结果将返回False ,而不是正确的代理对象)。- 与
not self.__eq__(other) 不同,当self.__eq__ 返回NotImplemented 时(not self.__eq__(other) 将是额外的错误,因为NotImplemented 是真实的,所以当__eq__ 不知道如何进行比较时,__ne__ 将返回False 表示这两个对象是当事实上唯一被询问的对象不知道,这意味着默认值不相等时,则表示怀疑)如果您的
__eq__ 不使用NotImplemented 返回,这是有效的(没有意义的开销),如果它有时使用NotImplemented 返回,这会正确地处理它。而python版本检查意味着,如果类在python 3中是import ed,那么__ne__ 就没有定义,允许python的本地、高效的fallback__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 类的子类,则相反)。除了"交换"操作符的概念之外,操作符之间没有隐含的关系。即使是同一个类,返回 True 的LHS.__eq__(RHS) 也不意味着LHS.__ne__(RHS) 返回False (实际上,甚至不要求运算符返回布尔值;sqlachemy等窗体故意不返回,从而允许更具表现力的查询语法)。从python 3开始,默认的__ne__ 实现的行为是这样的,但它不是契约性的;您可以用不严格与__eq__ 对立的方式重写__ne__ 。这是如何应用于重载比较器的
因此,当您重载一个运算符时,有两个作业:好的。
如果您知道如何自己实现该操作,请仅使用自己对如何进行比较的知识进行比较(不要将隐式或显式委托给操作的另一方;这样做可能会导致不正确和/或无限递归,具体取决于您如何做) 如果您自己不知道如何实现该操作,请始终返回 NotImplemented ,这样python就可以委托给另一个操作数的实现。
not self.__eq__(other) 的问题
1
2 def __ne__(self, other):
return not self.__eq__(other)决不委托对方(如果
__eq__ 正确返回NotImplemented 则不正确)。当self.__eq__(other) 返回NotImplemented (即"truthy")时,你悄悄地返回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 的角度来看,它可能是错误的,since它甚至没有问过something_A_knows_nothing_about ;A() != something_A_knows_nothing_about 以True 结尾,但something_A_knows_nothing_about != A() 可以是False 或其他任何回报价值。好的。EDOCX1的问题(24)
1
2 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 ,而在后一种情况下,A() != Incomparable() 和Incomparable() != A() 返回False 。cx1〔41〕直接返回False 。但当A.__ne__ 作为return not self == other 执行时,A() != Incomparable() 返回True (因为A.__eq__ 返回,而不是NotImplemented 返回,那么Incomparable.__eq__ 返回False ,A.__ne__ 将其反转为True ,而Incomparable() != A() 返回False. 。好的。您可以在这里看到一个实际的例子。好的。
显然,对于
__eq__ 和__ne__ ,总是返回False 的类有点奇怪。但如前所述,__eq__ 和__ne__ 甚至不需要返回True 和False ;sqlacalchemy orm的类中有带比较器的类,这些比较器返回用于查询构建的特殊代理对象,而不是True 和False (如果在布尔上下文中进行评估,它们是"真实的",但它们不应该被评估在这种情况下)。好的。如果未能正确地重载
__ne__ ,您将破坏这种类型的类,如代码:好的。
1 results = session.query(MyTable).filter(MyTable.fieldname != MyClassWithBadNE())将工作(假设sqlAlchemy知道如何将
MyClassWithBadNE 插入到SQL字符串中;这可以通过类型适配器完成,而不需要MyClassWithBadNE 进行任何合作),将预期的代理对象传递给filter ,同时:好的。
1 results = session.query(MyTable).filter(MyClassWithBadNE() != MyTable.fieldname)号
将最终传递一个普通的
False ,因为self == other 返回一个代理对象,而not self == other 只是将真实的代理对象转换为False 。希望,filter 在处理像False 这样的无效参数时抛出了一个异常。虽然我相信许多人会争辩说,MyTable.fieldname 应该始终处于比较的左侧,但事实上,在一般情况下,没有任何程序性理由来执行这一点,正确的通用__ne__ 将以任何方式工作,而return not self == other 只在一种安排中工作。好的。好啊。
简短回答:是的(但请阅读文档以正确执行此操作)shadowRanger对
__ne__ 方法的实现是正确的(从某种意义上说,它的行为与默认的python 3实现完全相同):好的。
1
2
3
4
5
6
7 def __ne__(self, other):
result = self.__eq__(other)
if result is not NotImplemented:
return not result
return NotImplementedAaron Hall对
__ne__ 方法的实现not self == other 是不正确的,因为它不能返回NotImplemented (not NotImplemented 是False ,因此具有优先权的__ne__ 方法永远不能落在没有优先权的__ne__ 方法上。not self == other 曾经是__ne__ 方法的默认python 3实现,但它是一个bug,正如shadowranger注意到的那样,它在2015年1月的python3.4中得到了纠正(见21408期)。好的。比较运算符的实现python 3的python语言参考在其第三章数据模型中指出:好的。
object.__lt__(self, other)
object.__le__(self, other)
object.__eq__(self, other)
object.__ne__(self, other)
object.__gt__(self, other)
object.__ge__(self, other) Ok.
These are the so-called"rich comparison" methods. The correspondence
between operator symbols and method names is as follows:x calls
x.__lt__(y) ,x<=y callsx.__le__(y) ,x==y callsx.__eq__(y) ,
x!=y callsx.__ne__(y) ,x>y callsx.__gt__(y) , andx>=y
callsx.__ge__(y) .Ok.
A rich comparison method may return the singleton
NotImplemented if
it does not implement the operation for a given pair of arguments.Ok.
There are no swapped-argument versions of these methods (to be used
when the left argument does not support the operation but the right
argument does); rather,__lt__() and__gt__() are each other’s
reflection,__le__() and__ge__() are each other’s reflection, and
__eq__() and__ne__() are their own reflection. If the operands
are of different types, and right operand’s type is a direct or
indirect subclass of the left operand’s type, the reflected method of
the right operand has priority, otherwise the left operand’s method
has priority. Virtual subclassing is not considered.Ok.
号
将其转换为python代码给出(使用
operator_eq 表示== 、operator_ne 表示!= 、operator_lt 表示< 、operator_gt 表示> 、operator_le 表示<= 和operator_ge 表示>= :好的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106 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号比较方法的默认实现
文件还增加了:好的。
By default,
__ne__() delegates to__eq__() and inverts the result
unless it isNotImplemented . There are no other implied
relationships among the comparison operators, for example, the truth
of(x does not imply x<=y .Ok.
号
比较方法(
__eq__ 、__ne__ 、__lt__ 、__gt__ 、__le__ 、__ge__ 的默认实现方式如下:好的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 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 实现的行为来证明如下:好的。
__eq__ 方法返回NotImplemented ;__eq__ 方法返回的值与NotImplemented 不同。默认实现
让我们看看当
A.__ne__ 方法使用默认实现,而A.__eq__ 方法返回NotImplemented 时会发生什么:好的。
1
2
3
4
5
6
7
8
9
10
11 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 不同时会发生什么:好的。
1
2
3
4
5
6
7
8
9
10
11
12
13 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 实施让我们看看当用
not self == other 实现覆盖A.__ne__ 方法的默认实现时会发生什么,A.__eq__ 方法返回NotImplemented 时会发生什么:好的。
1
2
3
4
5
6
7
8
9
10
11
12
13 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 。好的。现在让我们看看当用
not self == other 实现覆盖A.__ne__ 方法的默认实现时会发生什么,A.__eq__ 方法返回的值与NotImplemented 不同:好的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 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 。好的。由于当
__eq__ 方法返回NotImplemented 时,此实现无法复制__ne__ 方法默认实现的行为,因此是不正确的。好的。好啊。如果所有的
__eq__ 、__ne__ 、__lt__ 、__ge__ 、__le__ 、__gt__ 对这个类都有意义,那么只需执行__cmp__ 。否则,就照你说的做吧,因为丹尼尔·迪帕奥洛说的那句话(当时我在测试它,而不是查找它;)