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 variable—the 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.