Почему я не могу использовать метод cmp в Python 3 как для Python 2?

следующий фрагмент кода

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 ответов


вам нужно предоставить богатые методы сравнения для заказа в Python 3, которые являются __lt__, __gt__, __le__, __ge__, __eq__ и __ne__. См. также: PEP 207 -- богатые сравнения.

__cmp__ и нет больше не используется.


более конкретно, __lt__ принимает self и other в качестве аргументов, и нужно ли возвращать 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):
        ...

Это было серьезное и преднамеренное изменение в Python 3. См.здесь для более подробной информации.


в Python3 шесть богатых операторов сравнения

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

необходимо обеспечить индивидуально. Это можно сократить с помощью functools.total_ordering.

это, однако, оказывается довольно нечитаемым и непрактичным большую часть времени. Тем не менее, вы должны поместить аналогичные фрагменты кода в 2 функции - или использовать дополнительный вспомогательный func.

поэтому в основном я предпочитаю использовать класс mixin PY3__cmp__ показано ниже. Это восстанавливает сингл __cmp__ метод framework, который был и есть довольно ясный и практичный в большинстве случаев. Все еще можно переопределить выбранные богатые сравнения.

ваш пример просто стало:

 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