Learning Python - Mark Lutz [399]
cb() # On event prints 'blue'
Note that a lambda is not required here, because a bound method reference by itself already defers a call till later (again, more on bound methods in Chapter 30). This technique is simpler, but less general than overloading calls with __call__; again, watch for more about bound methods in the next chapter.
You’ll also see another __call__ example in Chapter 31, where we will use it to implement something known as a function decorator—a callable object often used to add a layer of logic on top of an embedded function. Because __call__ allows us to attach state information to a callable object, it’s a natural implementation technique for a function that must remember and call another function.
Comparisons: __lt__, __gt__, and Others
As suggested in Table 29-1, classes can define methods to catch all six comparison operators: <, >, <=, >=, ==, and !=. These methods are generally straightforward to use, but keep the following qualifications in mind:
Unlike the __add__/__radd__ pairings discussed earlier, there are no right-side variants of comparison methods. Instead, reflective methods are used when only one operand supports comparison (e.g., __lt__ and __gt__ are each other’s reflection).
There are no implicit relationships among the comparison operators. The truth of == does not imply that != is false, for example, so both __eq__ and __ne__ should be defined to ensure that both operators behave correctly.
In Python 2.6, a __cmp__ method is used by all comparisons if no more specific comparison methods are defined; it returns a number that is less than, equal to, or greater than zero, to signal less than, equal, and greater than results for the comparison of its two arguments (self and another operand). This method often uses the cmp(x, y) built-in to compute its result. Both the __cmp__ method and the cmp built-in function are removed in Python 3.0: use the more specific methods instead.
We don’t have space for an in-depth exploration of comparison methods, but as a quick introduction, consider the following class and test code:
class C:
data = 'spam'
def __gt__(self, other): # 3.0 and 2.6 version
return self.data > other
def __lt__(self, other):
return self.data < other
X = C()
print(X > 'ham') # True (runs __gt__)
print(X < 'ham') # False (runs __lt__)
When run under Python 3.0 or 2.6, the prints at the end display the expected results noted in their comments, because the class’s methods intercept and implement comparison expressions.
The 2.6 __cmp__ Method (Removed in 3.0)
In Python 2.6, the __cmp__ method is used as a fallback if more specific methods are not defined: its integer result is used to evaluate the operator being run. The following produces the same result under 2.6, for example, but fails in 3.0 because __cmp__ is no longer used:
class C:
data = 'spam' # 2.6 only
def __cmp__(self, other): # __cmp__ not used in 3.0
return cmp(self.data, other) # cmp not defined in 3.0
X = C()
print(X > 'ham') # True (runs __cmp__)
print(X < 'ham') # False (runs __cmp__)
Notice that this fails in 3.0 because __cmp__ is no longer special, not because the cmp built-in function is no longer present. If we change the prior class to the following to try to simulate the cmp call, the code still works in 2.6 but fails in 3.0:
class C:
data = 'spam'
def __cmp__(self, other):
return (self.data > other) - (self.data < other)
* * *
Note
So why, you might be asking, did I just show you a comparison method that is no longer supported in 3.0? While it would be easier to erase history entirely, this book is designed to support both 2.6 and 3.0 readers. Because __cmp__ may appear in code 2.6 readers must reuse or maintain, it’s fair game in this book. Moreover, __cmp__ was removed more abruptly than the __getslice__ method described earlier, and so may endure longer. If you use 3.0, though, or care about running your code under 3.0 in the future, don’t use __cmp__ anymore: use the more specific comparison methods instead.