Recipe 4.16. Using a Dictionary to Dispatch Methods or Functions
Credit: Dick Wall
Problem
You need to execute different
pieces of code depending on the value of some control
variablethe kind of problem that in some other languages you
might approach with a case statement.
Solution
Object-oriented programming, thanks
to its elegant concept of dispatching, does away with many (but not
all) needs for case statements. In Python,
dictionaries, and the fact that functions are first-class objects (in
particular, functions can be values in a dictionary), conspire to
make the full problem of "case
statements" easier to solve. For example, consider
the following snippet of code:
animals = [ ]
number_of_felines = 0
def deal_with_a_cat( ):
global number_of_felines
print "meow"
animals.append('feline')
number_of_felines += 1
def deal_with_a_dog( ):
print "bark"
animals.append('canine')
def deal_with_a_bear( ):
print "watch out for the *HUG*!"
animals.append('ursine')
tokenDict = {
"cat": deal_with_a_cat,
"dog": deal_with_a_dog,
"bear": deal_with_a_bear,
}
# Simulate, say, some words read from a file
words = ["cat", "bear", "cat", "dog"]
for word in words:
# Look up the function to call for each word, and call it
return tokenDict[word]( )
nf = number_of_felines
print 'we met %d feline%s' % (nf, 's'[nf==1:])
print 'the animals we met were:', ' '.join(animals)
Discussion
The key idea in this recipe is to construct a dictionary with string
(or other) values as keys, and bound-methods, functions, or other
callables as values. At each step of execution, we use the string
keys to select which callable to execute and then call it. This
approach can be used as a kind of generalized case
statement.It's embarrassingly simple (really!), but I use this
technique often. You can also use bound-methods or other callables
instead of functions. If you use unbound methods, you need to pass an
appropriate object as the first actual argument when you do call
them. More generally, you can store, as the
dictionary's values, tuples including both a
callable and arguments to pass to the callable.I primarily use this technique in places where in other languages, I
might want a case, switch, or
select statement. For example, I use it to
implement a poor man's way to
parse command files (e.g., an X10 macro control file).
See Also
The Library Reference section on mapping
types; the Reference Manual section on bound
and unbound methods; Python in a Nutshell
about both dictionaries and callables.