Reputation: 1841
I have a supposedly simple situation where I am trying to sort a list that contains a mix of class instances, and None. I've implemented the lt method of the class, but I'm still getting an error:
TypeError: '<' not supported between instances of 'NoneType' and 'test_class
Here's how I'm currently doing it:
class test_class:
def __init__(self, num):
self.num = num
def __lt__(self, other):
if other is None:
return False
else:
return self.num < other.num
def __eq__(self, other):
if other is None:
return False
else:
return self.num == other.num
tc1 = test_class(1)
tc2 = test_class(2)
sorted([tc1, tc2, None])
... which produces the above-mentioned error. Could anyone kindly point out what I'm doing wrong? In some sort of idealized reality where programming languages work in a common-sense way, I would have thought that the 'if other is None' bit should handle a comparison with None.
Thanks in advance!
Upvotes: 0
Views: 62
Reputation: 54193
Note that your error is not
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'test_class' and 'NoneType'
but instead
...between instances of 'NoneType' and 'test_class'
The ordering matters. None
does not implement a __lt__
method that knows how to compare to a test_class
. However Python is smart enough to use the other class's __gt__
in this case.
class TestClass(object):
def __init__(self, num):
self.num = num
def __lt__(self, other):
if other is None:
return False
else:
return self.num < other.num
def __gt__(self, other):
if other is None:
return True
return self.num > other.num
def __eq__(self, other):
if other is None:
return False
else:
return self.num == other.num
What's more, functools.total_ordering
can be used to decorate your class so you only have to define __eq__
and one of __lt__
, __le__
, __gt__
, __ge__
and the rest will be auto generated for you.
import functools
@functools.total_ordering
class TestClass(object):
def __init__(self, num):
self.num = num
def __lt__(self, other):
if other is None: return False
return self.num < other.num
def __eq__(self, other):
return isinstance(other, type(self)) and self.num == other.num
# I refactored this to be a little nicer
Now TestClass()
acts as if __gt__
, __ge__
, and __le__
are all defined, even though you only have to define one.
Upvotes: 1