[Tutor] Using dictionaries to call functione

Danny Yoo dyoo@hkn.eecs.berkeley.edu
Fri, 17 Aug 2001 11:17:07 -0700 (PDT)


On Fri, 17 Aug 2001, dman wrote:

> On Fri, Aug 17, 2001 at 09:14:23AM -0500, Kevin McCormick wrote:
> | I have seen several examples of using dictionaries to call functions.  I
> | believe the function name is the dictionary key, and its values are the
> | associated arguments.  Yet, I find this method difficult to understand. 
> | For example, I would like to pass a list of words and parameters to a
> | function, and for each word in the list, call word(parameter1,
> | parameter2, ...) referenced in a dictionary which somehow calls the
> | associated function (called a "dispatch table", I think).  What are the
> | basic concepts of this method?
> 
> In python, functions are objects just like everything else.  This
> means that they can be stored in a dictionary.  The key can be
> anything you want it to be, but is often a string or integer that is
> directly related to some input.  The value is just a reference to the
> function.  The client would retrieve that function object from the
> dictionary then call it just as it would any other function.  The only
> trick is to make sure that the client knows what sort of arguments the
> function expects.  Here is an example :
> 
> def func1( p1 , p2 ) :
>     print "func1 called : %s , %s" % (p1 , p2)
> 
> def func2( p1 , p2 ) :
>     print "func2 called : %s , %s" % (p1 , p2)
> 
> 
> dispatch_table = {
>     "hello" : func1 ,
>     "bye" : func2 
>     }



We can also write this so that the dispatcher doesn't even think about how
many arguments each function takes in:

###
def callFunction(function_name, arguments):
    the_func = dispatch_table[function_name]
    the_func(*arguments)

if __name__ == "__main__" :
    import sys    
    if not dispatch_table.has_key( sys.argv[1] ) :
        print "Unknown command '%s'" % sys.argv[1]
        sys.exit( 1 )
    callFunction(sys.argv[1], sys.argv[2:])
###

The star in front of 'arguments' is what tells Python to send off the
elements of 'arguments' to the_func(). 


Although this simplifies the code a little, now the program will die if we
give the function too many arguments, or not enough.  That's where
exception handling comes in: we can put the code in a try/except block
that knows what to do when the user doesn't give enough arguments.



Here's another example that demonstrates a little bit of exception
handling as well as the dispatch approach:

###
"""This is a small example of dispatch-based programming.

Danny Yoo (dyoo@hkn.eecs.berkeley.edu)
"""


import sys

def addCommand(*args):
    sum = 0
    for thing in args: sum += float(thing)
    print "The sum is", sum


def uppercaseCommand(*args):
    for thing in args:
        print thing.upper(),
    print


def quitCommand(*args):
    print "Goodbye!"
    sys.exit(0)


def helpCommand(*args):
    print "Here are your available commands: "
    for key in DISPATCH_TABLE.keys():
        description, function = DISPATCH_TABLE[key]
        print "\t%s: %s" % (key, description)


"""Our dispatch table has function names as the keys, with
(description, function) tuples as values."""
DISPATCH_TABLE = { 'add' : ('Add numbers together.', addCommand),
                   'uc' : ('Uppercase arguments.', uppercaseCommand),
                   'quit' : ('Quit.', quitCommand),
                   'help' : ('You are looking at it.', helpCommand) }


def evaluate(command_line):
    try:
        function_name, arguments = (command_line.split()[0],
                                    command_line.split()[1:])
        if DISPATCH_TABLE.has_key(function_name):
            description, function = DISPATCH_TABLE[function_name]
            function(*arguments)
        else:
            print "I don't know about '%s'." % function_name
            print "Try typing 'help' at the prompt.\n"
    except SystemExit:
        raise SystemExit
    except (Exception), e:
        print "Ooops: %s" % e


if __name__ == "__main__" :
    while 1:
        sys.stdout.write("Command me >>> ")
        sys.stdout.flush()
        try:
            line = raw_input()
        except EOFError:
            evaluate("quit")
        if line: evaluate(line)
###



And a sample run:

###
[dyoo@tesuque dyoo]$ python dispatcher.py
Command me >>> hello
I don't know about 'hello'.
Try typing 'help' at the prompt.

Command me >>> help
Here are your available commands: 
	uc: Uppercase arguments
	help: You are looking at it.
	add: Add numbers together
	quit: Quit
Command me >>> uc this is a test of the emergency broadcast system
THIS IS A TEST OF THE EMERGENCY BROADCAST SYSTEM
Command me >>> add 3 4 5 6 7
The sum is 25.0
Command me >>> add three one four one five nine two six
Ooops: invalid literal for float(): three
Command me >>> quit
Goodbye!
###