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 très bien dans Python 2, mais dans Python 3 je reçois 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()
Cela ne fonctionne que pour ==
et !=
.
Vous devez fournir les méthodes de comparaison riches pour la commande dans Python 3, qui sont __lt__
, __gt__
, __le__
, __ge__
, __eq__
et __ne__
. Voir aussi: PEP 207 - Comparaisons riches .
__cmp__
n'est plus plus utilisé.
Plus précisement, __lt__
prend self
et other
comme arguments, et doit indiquer 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 implémentation de comparaison raisonnable, mais il est difficile de dire ce que vous vouliez.)
Donc, si vous avez la situation suivante:
p1 = Point(1, 2)
p2 = Point(3, 4)
p1 < p2
Cela équivaudra à:
p1.__lt__(p2)
qui retournerait True
.
__eq__
renverrait True
si les points sont égaux et False
sinon. Les autres méthodes fonctionnent de manière analogue.
Si vous utilisez functools.total_ordering
décorateur, il vous suffit d'implémenter par exemple les __lt__
et __eq__
méthodes:
from functools import total_ordering
@total_ordering
class Point(object):
def __lt__(self, other):
...
def __eq__(self, other):
...
Ce fut un changement majeur et délibéré dans Python 3. Voir ici pour plus de détails.
- Les opérateurs de comparaison de commande (
<
,<=
,>=
,>
) Lèvent une exceptionTypeError
lorsque les opérandes n'ont pas de ordre naturel significatif. Ainsi, des expressions comme1 < ''
,0 > None
Oulen <= len
Ne sont plus valides, et par exempleNone < None
LèveTypeError
au lieu de renvoyerFalse
. 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 entre eux. Notez que cela ne s'applique pas aux opérateurs==
Et!=
: Les objets de types incomparables différents se comparent toujours inégaux entre eux.builtin.sorted()
etlist.sort()
n'acceptent plus l'argumentcmp
fournissant une fonction de comparaison. Utilisez plutôt l'argumentkey
. N.B. les argumentskey
etreverse
sont désormais "mot clé uniquement".- La fonction
cmp()
doit être traitée comme disparue et la méthode spéciale__cmp__()
n'est plus prise en charge. Utilisez__lt__()
pour le tri,__eq__()
avec__hash__()
, et d'autres comparaisons riches si nécessaire. (Si vous avez vraiment besoin de la fonctionnalitécmp()
, vous pouvez utiliser l'expression(a > b) - (a < b)
Comme équivalent pourcmp(a, b)
.)
En 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)
doit être fourni individuellement. Cela peut être abrégé en utilisant functools.total_ordering
.
Cela s'avère cependant assez illisible et peu pratique la plupart du temps. Vous devez toujours mettre des morceaux de code similaires dans 2 fonctions - ou utiliser une autre fonction d'assistance.
Donc, je préfère surtout utiliser la classe mixin PY3__cmp__
indiqué ci-dessous. Cela rétablit le single __cmp__
cadre de méthode, qui était et est assez clair et pratique dans la plupart des cas. On peut toujours remplacer les comparaisons riches sélectionnées.
Votre exemple deviendrait simplement:
class point(PY3__cmp__):
...
# unchanged code
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