64

下面的一段代码

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

它仅适用于==!=

4

3 回答 3

87

您需要在 Python 3 中提供丰富的排序比较方法,即 __lt__, __gt__, __le__, __ge__, __eq__, 和__ne__. 另请参阅:PEP 207 - 丰富的比较

__cmp__不再使用。


更具体地说,__lt__selfandother作为参数,并且需要返回是否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__and__eq__方法:

from functools import total_ordering

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

    def __eq__(self, other):
        ...
于 2011-11-26T07:41:21.893 回答
15

这是 Python 3 中一个重大且有意的更改。有关更多详细信息,请参见此处

  • 当操作数没有有意义的自然排序时,排序比较运算符 ( <, <=, >=, >) 会引发异常。因此,像, orTypeError这样的表达式不再有效,例如raises而不是返回。一个推论是对异构列表进行排序不再有意义——所有元素必须相互可比。请注意,这不适用于and运算符:不同类型的对象总是比较不相等。1 < ''0 > Nonelen <= lenNone < NoneTypeErrorFalse==!=
  • builtin.sorted()并且list.sort()不再接受cmp提供比较函数的参数。请改用该key参数。注意keyreverse参数现在是“仅关键字”。
  • cmp()功能应视为消失,__cmp__()不再支持特殊方法。根据需要用于__lt__()排序、__eq__()with__hash__()和其他丰富的比较。(如果你真的需要这个cmp()功能,你可以使用表达式(a > b) - (a < b)作为 . 的等价物cmp(a, b)。)
于 2011-11-26T07:36:23.063 回答
9

Python3 中的六种丰富的比较运算符

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

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

然而,这在大多数情况下被证明是相当不可读和不切实际的。您仍然必须将类似的代码片段放入 2 个函数中 - 或使用进一步的辅助函数。

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

您的示例将变为:

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

PY3__cmp__ 混合类:

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
于 2016-08-26T12:28:22.717 回答