我有一堂课,我想覆盖 __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.cobject_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 NotImplementedFalse),因此 __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有一些有关超载运营商的一般规则,尤其是比较操作员:

  1. (适用于所有操作员)运行时 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的课)
  2. 除了“交换”操作员的想法之外,操作员之间没有隐含的关系。即使例如同一类, LHS.__eq__(RHS) 返回 True 不暗示 LHS.__ne__(RHS) 返回 False (实际上,操作员甚至不需要返回布尔值;像sqlalchemy这样的Orms无意地不返回,允许更具表现力的查询语法)。截至Python 3,默认值 __ne__ 实施方式是这种方式,但这不是合同;您可以覆盖 __ne__ 以不严格的对立的方式 __eq__.

这如何适用于超载比较器

因此,当您超载操作员时,您有两个工作:

  1. 如果您知道如何自己实施操作,请使用 只要 您对如何进行比较的了解(切勿隐式或明确地委派到操作的另一侧;这样做的风险不正确和/或无限递归,具体取决于您的工作方式)
  2. 如果你 知道如何自己实施操作, 总是 返回 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 NotImplementedFalse),因此 __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 NotImplementedFalse (作为 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__"
  1. != 呼叫 A.__ne__.
  2. A.__ne__ 呼叫 A.__eq__.
  3. A.__eq__ 返回 NotImplemented.
  4. != 呼叫 B.__ne__.
  5. 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
  1. != 呼叫 A.__ne__.
  2. A.__ne__ 呼叫 A.__eq__.
  3. A.__eq__ 返回 True.
  4. != 返回 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
  1. != 呼叫 A.__ne__.
  2. A.__ne__ 呼叫 ==.
  3. == 呼叫 A.__eq__.
  4. A.__eq__ 返回 NotImplemented.
  5. == 呼叫 B.__eq__.
  6. B.__eq__ 返回 NotImplemented.
  7. == 返回 A() is B(), , 那是 False.
  8. 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
  1. != 呼叫 A.__ne__.
  2. A.__ne__ 呼叫 ==.
  3. == 呼叫 A.__eq__.
  4. A.__eq__ 返回 True.
  5. A.__ne__ 返回 not True, , 那是 False.

默认实现的 __ne__ 方法还返回 False 在这种情况下。

由于此实现未能复制默认实现的行为 __ne__ 方法时 __eq__ 方法返回 NotImplemented, ,这是不正确的。

如果全部 __eq__, __ne__, __lt__, __ge__, __le__, , 和 __gt__ 对班级有意义,然后实施 __cmp__ 反而。否则,像您一样做,因为丹尼尔·迪波洛(Daniel Dipaolo)说的一点(当我在测试它而不是查找;))

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top