class Foo(object):
def __init__(self, x):
self._x = x
def __cmp__(self, other):
if type(other) == Foo:
return cmp(self._x, other._x)
else:
raise TypeError("Foo cannot be compared to %s"%str(type(other))) f1 = Foo(1)
f2 = Foo(2)
print 'f1 is smaller than f2:', f1 < f2 # True
print 'f1 is larger than f2:', f1 > f2 # False
print 'f1 is equal to f2:', f1 == f2 # False
print 'f1 is None:', f1 == None # Crash!
This code crashes in the final statement, because the comparison to None calls the __cmp__ method, and it has no way of comparing to None. This could of course be fixed by adding "if other == None: return -1" but the right way to fix this would be by overloading another method called __eq__ that is used to test for object equality.
class Foo(object):
def __init__(self, x):
self._x = x
def __eq__(self, other):
if type(other) == Foo:
return cmp(self, other) == 0
else:
return False
def __cmp__(self, other):
if type(other) == Foo:
return cmp(self._x, other._x)
else:
raise TypeError("Foo cannot be compared to %s"%str(type(other)))
f1 = Foo(1)
f2 = Foo(2)
print 'f1 is smaller than f2:', f1 < f2 # True print 'f1 is larger than f2:', f1 > f2 # False
print 'f1 is equal to f2:', f1 == f2 # False
print 'f1 is None:', f1 == None # False
Now the comparison to None (or in fact to any object that is not of type Foo) is caught by the __eq__ method, and comparisons to other type Foo objects are correctly forwarded to the __cmp__ method.
Hey man,
ReplyDeletethanks a lot! I just stumbeled over this compare to None problem and thought about a nice solution.
You saved me quite some time, and your solution is pretty elegant, too.
def __cmp__(self, other):
ReplyDeleteif type(other) == Foo:
return cmp(self._x, other._x)
else:
raise TypeError("Second argument isn't Foo class")
What about else in __cmp__?
You are right. Otherwise the behavior when using < and > is undefined when types do not match. Thanks.
ReplyDeletecannot be compared to
ReplyDelete