The following piece of code
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))
works fine in Python 2, but in Python 3 I get an error:
>>> 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()
It only works for == and !=.
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
You need to provide the rich comparison methods for ordering in Python 3, which are __lt__, __gt__, __le__, __ge__, __eq__, and __ne__. See also: PEP 207 — Rich Comparisons.
__cmp__ is no longer used.
More specifically, __lt__ takes self and other as arguments, and needs to return whether self is less than other. For example:
class Point(object):
...
def __lt__(self, other):
return ((self.x < other.x) and (self.y < other.y))
(This isn’t a sensible comparison implementation, but it’s hard to tell what you were going for.)
So if you have the following situation:
p1 = Point(1, 2) p2 = Point(3, 4) p1 < p2
This will be equivalent to:
p1.__lt__(p2)
which would return True.
__eq__ would return True if the points are equal and False otherwise. The other methods work analogously.
If you use the functools.total_ordering decorator, you only need to implement e.g. the __lt__ and __eq__ methods:
from functools import total_ordering
@total_ordering
class Point(object):
def __lt__(self, other):
...
def __eq__(self, other):
...
Method 2
This was a major and deliberate change in Python 3. See here for more details.
- The ordering comparison operators (
<,<=,>=,>) raise aTypeErrorexception when the operands don’t have a meaningful natural ordering. Thus, expressions like1 < '',0 > Noneorlen <= lenare no longer valid, and e.g.None < NoneraisesTypeErrorinstead of returningFalse. A corollary is that sorting a heterogeneous list no longer makes sense – all the elements must be comparable to each other. Note that this does not apply to the==and!=operators: objects of different incomparable types always compare unequal to each other.builtin.sorted()andlist.sort()no longer accept thecmpargument providing a comparison function. Use thekeyargument instead. N.B. thekeyandreversearguments are now “keyword-only”.- The
cmp()function should be treated as gone, and the__cmp__()special method is no longer supported. Use__lt__()for sorting,__eq__()with__hash__(), and other rich comparisons as needed. (If you really need thecmp()functionality, you could use the expression(a > b) - (a < b)as the equivalent forcmp(a, b).)
Method 3
In Python3 the six rich comparison operators
__lt__(self, other) __le__(self, other) __eq__(self, other) __ne__(self, other) __gt__(self, other) __ge__(self, other)
must be provided individually. This can be abbreviated by using functools.total_ordering.
This however turns out rather unreadable and unpractical most of the time. Still you have to put similar code pieces in 2 funcs – or use a further helper func.
So mostly I prefer to use the mixin class PY3__cmp__ shown below. This reestablishes the single __cmp__ method framework, which was and is quite clear and practical in most cases. One can still override selected rich comparisons.
Your example would just become:
class point(PY3__cmp__):
...
# unchanged code
The PY3__cmp__ mixin class:
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
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0