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

时间:2011-11-26 07:27:30

标签: python python-3.x python-2.x partial-ordering

以下代码

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))

在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()

它仅适用于==!=

3 个答案:

答案 0 :(得分:48)

您需要在Python 3中提供丰富的排序比较方法,即__lt____gt____le____ge____eq____ne__。另见:PEP 207 -- Rich Comparisons

__cmp__ 没有更长时间使用。


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

class Point(object):
    ...
    def __lt__(self, other):
        return ((self.x < other.x) and (self.y < other.y))

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

因此,如果您遇到以下情况:

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

p1 < p2

这相当于:

p1.__lt__(p2)

将返回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):
        ...

答案 1 :(得分:11)

这是Python 3中一项重大而深思熟虑的更改。有关详细信息,请参阅here

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

答案 2 :(得分:7)

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

__lt__(self, other) 
__le__(self, other) 
__eq__(self, other) 
__ne__(self, other) 
__gt__(self, other) 
__ge__(self, other) 

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

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

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

你的例子就变成了:

 class point(PY3__cmp__):
      ... 
      # unchanged code

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