为什么我不能在Python 3中使用方法__cmp__和Python 2一样?

40 python python-2.x partial-ordering python-3.x

下面这段代码

class point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def dispc(self):
        return ('(' + str(self.x) + ',' + str(self.y) + ')')

    def __cmp__(self, other):
        return ((self.x > other.x) and (self.y > other.y))
Run Code Online (Sandbox Code Playgroud)

在Python 2中工作正常,但在Python 3中我收到一个错误:

>>> p=point(2,3)
>>> q=point(3,4)
>>> p>q
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: point() > point()
Run Code Online (Sandbox Code Playgroud)

它只适用于==!=.

Jes*_*lon 54

你需要为Python 3中,这是订货提供丰富的比较方法 __lt__,__gt__,__le__,__ge__,__eq__,和__ne__.另见:PEP 207 - 丰富的比较.

__cmp__不是不再使用.


更具体地说,__lt__selfother作为参数,并且需要返回是否self小于other.例如:

class Point(object):
    ...
    def __lt__(self, other):
        return ((self.x < other.x) and (self.y < other.y))
Run Code Online (Sandbox Code Playgroud)

(这不是一个合理的比较实现,但很难说出你想要的是什么.)

所以如果你有以下情况:

p1 = Point(1, 2)
p2 = Point(3, 4)

p1 < p2
Run Code Online (Sandbox Code Playgroud)

这相当于:

p1.__lt__(p2)
Run Code Online (Sandbox Code Playgroud)

哪会回来True.

__eq__True如果积分相等则会返回False.其他方法类似地工作.


如果你使用functools.total_ordering装饰器,你只需要实现例如__lt____eq__方法:

from functools import total_ordering

@total_ordering
class Point(object):
    def __lt__(self, other):
        ...

    def __eq__(self, other):
        ...
Run Code Online (Sandbox Code Playgroud)

  • 现在您需要定义“__hash__”以在集合中使用您的对象或作为字典键。 (2认同)
  • 感谢您提供有关使用“functools.total_ordering”的提示!我刚刚在Python 3.6上尝试了一下,我只需要定义`__lt__(self, other)`方法。(可能是因为如果“a &lt; b”和“b &lt; a”都为假,那么“a == b”必定为真。) (2认同)

Ned*_*ily 12

这是Python 3中一个重大而深思熟虑的变化.有关更多详细信息,请参见此处.

  • 排序比较操作符(<,<=,>=,>)提出一个TypeError例外,当操作数没有意义的自然顺序.因此,这样的表达式1 < '',0 > None或者len <= len不再有效,并且如None < None提高TypeError,而不是返回False.一个必然结果是,对异构列表进行排序不再有意义 - 所有元素必须相互比较.请注意,这不适用于==!=运算符:不同无比类型的对象总是相互比较不相等.
  • builtin.sorted()并且list.sort()不再接受cmp提供比较功能的参数.请改用key参数.NB keyreverse参数现在是"仅关键字".
  • cmp()函数应视为已消失,并且__cmp__()不再支持特殊方法.使用__lt__()的分类,__eq__()__hash__()根据需要,以及其他丰富的比较.(如果您确实需要该cmp()功能,可以使用该表达式(a > b) - (a < b)作为等效项cmp(a, b).)


kxr*_*kxr 7

在Python3中有六个丰富的比较运算符

__lt__(self, other) 
__le__(self, other) 
__eq__(self, other) 
__ne__(self, other) 
__gt__(self, other) 
__ge__(self, other) 
Run Code Online (Sandbox Code Playgroud)

必须单独提供.这可以通过使用缩写functools.total_ordering.

然而,这在大多数情况下变得相当难以理解和不实用.仍然你必须在2个函数中放入类似的代码片段 - 或者使用另一个辅助函数.

所以我更喜欢使用PY3__cmp__下面显示的mixin类.这重新__cmp__构建了单一方法框架,在大多数情况下,该框架非常清晰实用.人们仍然可以覆盖选定的丰富比较.

你的例子将成为:

 class point(PY3__cmp__):
      ... 
      # unchanged code
Run Code Online (Sandbox Code Playgroud)

PY3__cmp__ mixin类:

PY3 = sys.version_info[0] >= 3
if PY3:
    def cmp(a, b):
        return (a > b) - (a < b)
    # mixin class for Python3 supporting __cmp__
    class PY3__cmp__:   
        def __eq__(self, other):
            return self.__cmp__(other) == 0
        def __ne__(self, other):
            return self.__cmp__(other) != 0
        def __gt__(self, other):
            return self.__cmp__(other) > 0
        def __lt__(self, other):
            return self.__cmp__(other) < 0
        def __ge__(self, other):
            return self.__cmp__(other) >= 0
        def __le__(self, other):
            return self.__cmp__(other) <= 0
else:
    class PY3__cmp__:
        pass
Run Code Online (Sandbox Code Playgroud)

  • @theBuzzyCoder`bool`只是`int`的子类,所以`True`和`False`分别基本上是1和0.因为如果第一个参数小于第二个参数,`cmp`返回负值,如果参数相等则返回零,否则返回正值,你可以看到`False - False == 0`,'True - False = = 1`,并且`False - True == -1`为`cmp`提供正确的返回值. (3认同)