关于比较:Python,我应该基于__eq__实现__ne __()运算符吗?

Python, should I implement __ne__() operator based on __eq__?

我有一个类要在其中重写__eq__()运算符。我也应该重写__ne__()操作符似乎是有道理的,但是基于__eq__实现__ne__是否有意义?

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.

号简短回答:不,用==代替__eq__

在python 3中,默认情况下,!===的否定,因此甚至不需要编写__ne__,文档也不再是对编写__ne__的意见。好的。

一般来说,对于仅用于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本身不会根据另一个操作自动实现任何操作,因此,您应该根据==而不是__eq__来定义__ne__。例如。好的。

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 of x==y does not imply that x!=y is false. Accordingly, when
defining __eq__(), one should also define __ne__() so that the
operators will behave as expected.

Ok.

这意味着,如果我们用__eq__的倒数定义__ne__,我们可以得到一致的行为。好的。

文档的这一部分已针对python 3进行了更新:好的。

By default, __ne__() delegates to __eq__() and inverts the result
unless it is NotImplemented.

Ok.

在"新增内容"部分,我们看到这种行为发生了变化:好的。

  • != now returns the opposite of ==, unless == returns NotImplemented.

为了实现__ne__,我们更倾向于使用==操作符,而不是直接使用__eq__方法,这样,如果某个子类的self.__eq__(other)返回NotImplemented作为检查的类型,python将从文档中适当地检查other.__eq__(self):好的。NotImplemented对象

此类型只有一个值。有一个具有此值的对象。通过内置名称访问此对象埃多克斯1〔17〕。数值方法和富比较方法可能返回如果不实现操作数的操作,则为该值提供。(然后,解释器将尝试反射操作,或者其他一些回退,取决于运算符。)其真值为真的。好的。blockquote></

当给定的比较运算符丰富,如果他们是不一样的类型检查,如果otherPython是一个亚型,如果它是一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.cCPython的__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 return NotImplemented (not NotImplemented is False) 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 of x==y does not imply that x!=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中是imported,那么__ne__就没有定义,允许python的本地、高效的fallback __ne__实现(上面的C版本)接管。好的。为什么需要这个python重载规则

解释为什么你要这样做而不是其他的解决方案有些神秘。python有几个关于重载运算符的一般规则,尤其是比较运算符:好的。

  • (适用于所有操作员)运行LHS OP RHS时,尝试LHS.__op__(RHS),如果返回NotImplemented时,尝试RHS.__rop__(LHS)。例外:如果RHSLHS类的一个子类,那么首先测试RHS.__rop__(LHS)。在比较运算符的情况下,__eq____ne__是它们自己的"rop"(因此,__ne__的测试顺序是LHS.__ne__(RHS),然后是RHS.__ne__(LHS),如果RHSLHS类的子类,则相反)。
  • 除了"交换"操作符的概念之外,操作符之间没有隐含的关系。即使是同一个类,返回TrueLHS.__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_aboutA() != something_A_knows_nothing_aboutTrue结尾,但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__返回FalseA.__ne__将其反转为True,而Incomparable() != A()返回False.。好的。

    您可以在这里看到一个实际的例子。好的。

    显然,对于__eq____ne__,总是返回False的类有点奇怪。但如前所述,__eq____ne__甚至不需要返回TrueFalse;sqlacalchemy orm的类中有带比较器的类,这些比较器返回用于查询构建的特殊代理对象,而不是TrueFalse(如果在布尔上下文中进行评估,它们是"真实的",但它们不应该被评估在这种情况下)。好的。

    如果未能正确地重载__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 NotImplemented

    Aaron Hall对__ne__方法的实现not self == other是不正确的,因为它不能返回NotImplemented(not NotImplementedFalse,因此具有优先权的__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 calls x.__le__(y), x==y calls x.__eq__(y),
    x!=y calls x.__ne__(y), x>y calls x.__gt__(y), and x>=y
    calls x.__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 is NotImplemented. 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 NotImplementedFalse(因为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__。否则,就照你说的做吧,因为丹尼尔·迪帕奥洛说的那句话(当时我在测试它,而不是查找它;)