Recipe 4.16. Using a Dictionary to Dispatch Methods or FunctionsCredit: Dick Wall ProblemYou 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. SolutionObject-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) DiscussionThe 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 AlsoThe Library Reference section on mapping types; the Reference Manual section on bound and unbound methods; Python in a Nutshell about both dictionaries and callables. |