Learning Python - Mark Lutz [398]
>>> class Prod:
... def __init__(self, value): # Accept just one argument
... self.value = value
... def __call__(self, other):
... return self.value * other
...
>>> x = Prod(2) # "Remembers" 2 in state
>>> x(3) # 3 (passed) * 2 (state)
6
>>> x(4)
8
In this example, the __call__ may seem a bit gratuitous at first glance. A simple method can provide similar utility:
>>> class Prod:
... def __init__(self, value):
... self.value = value
... def comp(self, other):
... return self.value * other
...
>>> x = Prod(3)
>>> x.comp(3)
9
>>> x.comp(4)
12
However, __call__ can become more useful when interfacing with APIs that expect functions—it allows us to code objects that conform to an expected function call interface, but also retain state information. In fact, it’s probably the third most commonly used operator overloading method, behind the __init__ constructor and the __str__ and __repr__ display-format alternatives.
Function Interfaces and Callback-Based Code
As an example, the tkinter GUI toolkit (named Tkinter in Python 2.6) allows you to register functions as event handlers (a.k.a. callbacks); when events occur, tkinter calls the registered objects. If you want an event handler to retain state between events, you can register either a class’s bound method or an instance that conforms to the expected interface with __call__. In this section’s code, both x.comp from the second example and x from the first can pass as function-like objects this way.
I’ll have more to say about bound methods in the next chapter, but for now, here’s a hypothetical example of __call__ applied to the GUI domain. The following class defines an object that supports a function-call interface, but also has state information that remembers the color a button should change to when it is later pressed:
class Callback:
def __init__(self, color): # Function + state information
self.color = color
def __call__(self): # Support calls with no arguments
print('turn', self.color)
Now, in the context of a GUI, we can register instances of this class as event handlers for buttons, even though the GUI expects to be able to invoke event handlers as simple functions with no arguments:
cb1 = Callback('blue') # Remember blue
cb2 = Callback('green')
B1 = Button(command=cb1) # Register handlers
B2 = Button(command=cb2) # Register handlers
When the button is later pressed, the instance object is called as a simple function, exactly like in the following calls. Because it retains state as instance attributes, though, it remembers what to do:
cb1() # On events: prints 'blue'
cb2() # Prints 'green'
In fact, this is probably the best way to retain state information in the Python language—better than the techniques discussed earlier for functions (global variables, enclosing function scope references, and default mutable arguments). With OOP, the state remembered is made explicit with attribute assignments.
Before we move on, there are two other ways that Python programmers sometimes tie information to a callback function like this. One option is to use default arguments in lambda functions:
cb3 = (lambda color='red': 'turn ' + color) # Or: defaults
print(cb3())
The other is to use bound methods of a class. A bound method object is a kind of object that remembers the self instance and the referenced function. A bound method may therefore be called as a simple function without an instance later:
class Callback:
def __init__(self, color): # Class with state information
self.color = color
def changeColor(self): # A normal named method
print('turn', self.color)
cb1 = Callback('blue')
cb2 = Callback('yellow')
B1 = Button(command=cb1.changeColor) # Reference, but don't call
B2 = Button(command=cb2.changeColor) # Remembers function+self
In this case, when this button is later pressed it’s as if the GUI does this, which invokes the changeColor method to process the object’s state information:
object = Callback('blue')
cb = object.changeColor # Registered