在Python中,是否应该将_une_uu实现为对_eq_u的否定?

在Python中,是否应该将_une_uu实现为对_eq_u的否定?,python,comparison,operators,inequality,python-datamodel,Python,Comparison,Operators,Inequality,Python Datamodel,我有一个类,我想重写\uuuuueq\uuu方法。我也应该重写\uu\ne\uu方法,这似乎是有道理的。我应该将\uu ne\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu A类: 定义初始化(自我,状态): self.state=状态 定义(自身、其他): 返回self.state==other.state 定义(自身、其他): 返回非自我。均衡(其他) 是的,

我有一个类,我想重写
\uuuuueq\uuu
方法。我也应该重写
\uu\ne\uu
方法,这似乎是有道理的。我应该将
\uu ne\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

A类:
定义初始化(自我,状态):
self.state=状态
定义(自身、其他):
返回self.state==other.state
定义(自身、其他):
返回非自我。均衡(其他)

是的,那很好。事实上,当您定义
\uuuuu eq\uuuu
时,会敦促您定义
\uuuu ne\uuuuu

没有隐含的关系 在比较运算符中。这个
x==y的真理并不意味着
x=y
这是错误的。因此,在定义
\uuuu eq\uuuu()
,还应定义
\uuuu ne\uuuuuu()
,以便运算符按预期运行


在很多情况下(比如这一个),它会像否定
\uuuuueq\uuuuu
的结果一样简单,但并不总是如此。

如果所有
\uuuuuueq\uuuuu
\uuuu lt\uuuuuuu
\uge\uuge\ucode>、
/ucmp>代码都对类有意义,那么就实现代码吧。否则,就照你现在做的去做,因为Daniel DiPaolo说过(当我测试它而不是查找它时;)

Python,我应该基于
\uuu eq\uu
实现
\uu ne\uuu()操作符吗

简短回答:不要实现它,但如果必须,请使用
=
,而不是
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
在Python3中,
=
是默认情况下对
==
的否定,因此您甚至不需要编写
\uuu ne\uuuu
,文档也不再坚持编写一个

一般来说,对于Python3-only代码,除非需要掩盖父实现(例如,对于内置对象),否则不要编写代码

也就是说,请记住:

只有在以下情况下,
\uuu ne\uuuuuuu
方法才会从
\uuuu eq\uuuu
自动执行 超类中尚未定义
\uuu ne\uu
。所以,如果你是 从内置继承,最好同时覆盖这两个

如果需要代码在Python2中工作,请遵循Python2的建议,它在Python3中也可以正常工作

在Python2中,Python本身不会自动实现任何与另一个操作相关的操作-因此,您应该根据
==
而不是
\uuuuuu eq.
来定义
\uu ene.
。 例如

A类(对象):
定义(自身、其他):
返回self.value==other.value
定义(自身、其他):
return not self==其他#not `返回not self.uuu eq_uu(其他)`
看到证据了吗

  • 基于
    \uuu eq\uu
  • 根本没有在Python2中实现
    \uuu ne\uu
在下面的演示中提供了不正确的行为

长话短说 Python2的版本说:

比较运算符之间没有隐含的关系。这个
x==y的真理并不意味着
x=y
为假。因此,当 定义
\uuuu eq\uuuu()
,还应定义
\uu ne\uuuuu()
,以便 操作员将按预期操作

这意味着如果我们用
\uuuu eq\uuu
的倒数来定义
\uu ne\uuuu
,我们可以得到一致的行为

本节文档已针对以下内容进行了更新:

默认情况下,
\uuu ne\uuu()
委托给
\uu eq\uu()
,并反转结果 除非
未实施

在中,我们看到这种行为发生了变化:

  • =
    现在返回与
    ==
    相反的值,除非
    ==
    返回
    未实现
为了实现
\uuu ne\uuu
,我们更喜欢使用
=
操作符,而不是直接使用
\uuuu eq\uuu
方法,这样,如果子类的
self.\uu eq\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu(其他)
返回
未实现的
类型,Python将适当地检查
其他

NotImplemented
对象 此类型只有一个值。只有一个对象具有此值。通过内置名称访问此对象
未实施
。数值方法和丰富的比较方法可能返回 如果不执行操作数的操作,则返回此值 假如(然后解释器将尝试反射操作,或 其他一些回退,取决于运算符。)其真值为 对

当给定一个丰富的比较运算符时,如果它们不是相同的类型,Python会检查
other
是否是一个子类型,如果定义了该运算符,则首先使用
other
的方法(与
相反)。如果返回
NotImplemented
,则使用相反的方法。(它不会两次检查相同的方法。)使用
==
运算符允许此逻辑发生


期望 从语义上讲,您应该在检查平等性方面实现
\uu______
,因为您的类的用户希望以下函数对于一个类的所有实例都是等效的:

_等于(inst1,inst2)的定义否定: “”“始终应返回与not_equals相同的值(inst1,inst2)” 返回not inst1==inst2 def不等于(inst1,inst2): “”“始终应返回与_equals(inst1,inst2)的否定_相同的结果” 返回inst1!=inst2
也就是说,上述两个函数应始终返回相同的结果。但这取决于程序员

基于
\uuuuu eq\uuuu
定义
\uuuu ne\uuuuuuuu>时的意外行为演示:
首先,设置:

class BaseEqualable(对象):
assert not right1 == right2
assert not right2 == right1
assert right1 != right2
assert right2 != right1
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
assert not wrong1 == wrong2         # These are contradicted by the
assert not wrong2 == wrong1         # below unexpected behavior!
>>> 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
>>> right_py3_1, right_py3_1child = BaseEquatable(1), ChildComparablePy3(1)
>>> right_py3_1 != right_py3_1child # as evaluated in Python 2!
True
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
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
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
def __ne__(self, other):
    return not self.__eq__(other)
def __ne__(self, other):
    return not self == other
 results = session.query(MyTable).filter(MyTable.fieldname != MyClassWithBadNE())
 results = session.query(MyTable).filter(MyClassWithBadNE() != MyTable.fieldname)