61 votes

Pourquoi ne puis-je pas utiliser la méthode __cmp__ dans Python 3 comme dans Python 2 ?

Le morceau de code suivant

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

fonctionne bien en Python 2, mais en Python 3, j'obtiens une erreur :

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

Il ne fonctionne que pour == y != .

84voto

Jesse Dhillon Points 4136

Vous devez fournir les méthodes de comparaison riches pour l'ordonnancement en Python 3, qui sont les suivantes __lt__ , __gt__ , __le__ , __ge__ , __eq__ y __ne__ . Voir aussi : PEP 207 -- Comparaisons riches .

__cmp__ es pas de utilisé plus longtemps.


Plus précisément, __lt__ prend self y other comme arguments, et doit retourner si self est inférieur à other . Par exemple :

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

(Ce n'est pas une mise en œuvre de comparaison judicieuse, mais il est difficile de dire ce que vous vouliez faire).

Donc, si vous êtes dans la situation suivante :

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

p1 < p2

Cela équivaut à :

p1.__lt__(p2)

qui renverrait True .

__eq__ rendrait True si les points sont égaux et False autrement. Les autres méthodes fonctionnent de manière analogue.


Si vous utilisez le functools.total_ordering il vous suffit d'implémenter, par exemple, le décorateur __lt__ y __eq__ méthodes :

from functools import total_ordering

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

    def __eq__(self, other):
        ...

15voto

Ned Deily Points 40248

Il s'agit d'une modification majeure et délibérée dans Python 3. Voir aquí pour plus de détails.

  • Les opérateurs de comparaison d'ordre ( < , <= , >= , > ) soulève un TypeError exception lorsque les opérandes n'ont pas d'ordre naturel significatif. Ainsi, des expressions comme 1 < '' , 0 > None o len <= len ne sont plus valables, et par exemple None < None soulève TypeError au lieu de renvoyer False . Un corollaire est que le tri d'une liste hétérogène n'a plus de sens - tous les éléments doivent être comparables les uns aux autres. Notez que cela ne s'applique pas à la == y != opérateurs : les objets de types différents incomparables se comparent toujours de manière inégale.
  • builtin.sorted() y list.sort() n'acceptent plus les cmp argument fournissant une fonction de comparaison. Utilisez le key à la place. N.B. le key y reverse sont désormais des "mots-clés seulement".
  • El cmp() doit être traitée comme disparue, et la fonction __cmp__() Cette méthode spéciale n'est plus prise en charge. Utilisez __lt__() pour le tri, __eq__() con __hash__() et d'autres comparaisons riches si nécessaire. (Si vous avez vraiment besoin de la cmp() vous pourriez utiliser l'expression (a > b) - (a < b) comme l'équivalent de cmp(a, b) .)

9voto

kxr Points 31

Dans Python3, les six opérateurs de comparaison riches

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

doivent être fournis individuellement. Ceci peut être abrégé en utilisant functools.total_ordering .

Cependant, cela s'avère assez illisible et peu pratique la plupart du temps. Vous devez toujours mettre des morceaux de code similaires dans deux fonctions - ou utiliser une autre fonction d'aide.

C'est pourquoi je préfère utiliser la classe mixin PY3__cmp__ illustré ci-dessous. Cela rétablit l'unique __cmp__ qui était et reste assez clair et pratique dans la plupart des cas. On peut toujours passer outre certaines comparaisons riches.

Votre exemple deviendrait simplement :

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

La classe de mixage 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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X