98

I'm a python beginner, and I just learned a technique involving dictionaries and functions. The syntax is easy and it seems like a trivial thing, but my python senses are tingling. Something tells me this is a deep and very pythonic concept and I'm not quite grasping its importance. Can someone put a name to this technique and explain how/why it's useful?


The technique is when you have a python dictionary and a function that you intend to use on it. You insert an extra element into the dict, whose value is the name of the function. When you're ready to call the function you issue the call indirectly by referring to the dict element, not the function by name.

The example I'm working from is from Learn Python the Hard Way, 2nd Ed. (This is the version available when you sign up through Udemy.com; sadly the live free HTML version is currently Ed 3, and no longer includes this example).

To paraphrase:

# make a dictionary of US states and major cities
cities = {'San Diego':'CA', 'New York':'NY', 'Detroit':'MI'}

# define a function to use on such a dictionary
def find_city (map, city):
    # does something, returns some value
    if city in map:
        return map[city]
    else:
        return "Not found"

# then add a final dict element that refers to the function
cities['_found'] = find_city

Then the following expressions are equivalent. You can call the function directly, or by referencing the dict element whose value is the function.

>>> find_city (cities, 'New York')
NY

>>> cities['_found'](cities, 'New York')
NY

Can someone explain what language feature this is, and maybe where it comes to play in "real" programming? This toy exercise was enough to teach me the syntax, but didn't take me all the way there.

3
  • 15
    Why would this post be off-topic? It's a great algorithm and data structure concept question! Jan 9, 2013 at 20:52
  • I've seen (and done) some stuff like this in other languages. You could sort of look at it as a switch statement, but wrapped up nicely in a passable object with O(1) lookup time.
    – KChaloux
    Jan 9, 2013 at 21:17
  • 1
    I had a hunch there was something important & self-referential about including the function inside its own dict... see @dietbuddha's answer... but maybe not? Jan 10, 2013 at 22:31

5 Answers 5

119

Using a dict let's you translate the key into a callable. The key doesn't need to be hardcoded though, as in your example.

Usually, this is a form of caller dispatch, where you use the value of a variable to connect to a function. Say a network process sends you command codes, a dispatch mapping lets you translate the command codes easily into executable code:

def do_ping(self, arg):
    return 'Pong, {0}!'.format(arg)

def do_ls(self, arg):
    return '\n'.join(os.listdir(arg))

dispatch = {
    'ping': do_ping,
    'ls': do_ls,
}

def process_network_command(command, arg):
    send(dispatch[command](arg))

Note that what function we call now depends entirely on what the value is of command. The key doesn't have to match either; it doesn't even have to be a string, you could use anything that can be used as a key, and fits your specific application.

Using a dispatch method is safer than other techniques, such as eval(), as it limits the commands allowable to what you defined beforehand. No attacker is going to sneak a ls)"; DROP TABLE Students; -- injection past a dispatch table, for example.

5
  • 9
    @Martjin - Couldn't this be called an implementation of the 'Command Pattern' in that case? Seems like that's the concept the OP is trying to grasp?
    – PhD
    Jan 10, 2013 at 2:03
  • 3
    @PhD: Yeah, the example I built is a Command Pattern implementation; the dict acts as the dispatcher (command manager, invoker, etc.). Jan 10, 2013 at 7:02
  • Great top-level explanation, @Martijn, thanks. I think I get the "dispatch" idea. Jan 10, 2013 at 22:25
  • Is it possible to use such a technique with classes? For instance, doing mydict = {'api':Api()} allowing to call Api's methods with mydict['api'].testmethod()? I'm actually considering this, as it would allow me to call the same dictionary key with different underlying classes.
    – Lo Bellin
    Dec 15, 2020 at 14:21
  • 1
    @LoBellin: absolutely. Api() here produces an instance of the Api class, and is just another object. You can store that in a dictionary, mydict["api"] will retrieve there reference to it just like any other reference. There is no difference between api = Api(), api.testmethod() and mydict = {"api": Api()}, mydict["api"].testmethod() in that respect. Dec 17, 2020 at 13:44
36

@Martijn Pieters did a good job explaining the technique, but I wanted to clarify something from your question.

The important thing to know is that you are NOT storing "the name of the function" in the dictionary. You are storing a reference to the function itself. You can see this using a print on the function.

>>> def f():
...   print 1
... 
>>> print f
<function f at 0xb721c1b4>

f is just a variable that references the function you defined. Using a dictionary allows you to group like things, but it isn't any different from assigning a function to a different variable.

>>> a = f
>>> a
<function f at 0xb721c3ac>
>>> a()
1

Similarly, you can pass a function as an argument.

>>> def c(func):
...   func()
... 
>>> c(f)
1
1
  • 6
    Mentioning first class function would definitely help :-) Jan 9, 2013 at 20:32
13

Note that Python class is really just a syntax sugar for dictionary. When you do:

class Foo(object):
    def find_city(self, city):
        ...

when you call

f = Foo()
f.find_city('bar')

is really just the same as:

getattr(f, 'find_city')('bar')

which, after name resolution, is just the same as:

f.__class__.__dict__['find_city'](f, 'bar')

One useful technique is for mapping user input to callbacks. For example:

def cb1(...): 
    ...
funcs = {
    'cb1': cb1,
    ...
}
while True:
    input = raw_input()
    funcs[input]()

This can alternatively be written in class:

class Funcs(object):
    def cb1(self, a): 
        ...
funcs = Funcs()
while True:
    input = raw_input()
    getattr(funcs, input)()

whichever callback syntax is better depends on the particular application and programmer's taste. The former is more functional style, the latter is more object oriented. The former might feel more natural if you need to modify the entries in the function dictionary dynamically (perhaps based on user input); the latter might feel more natural if you have a set of different presets mapping that can be chosen dynamically.

4
  • I think this interchangeability is what made me think "pythonic", the fact that what you see on the surface is just a conventional way of presenting something much deeper. Maybe that's not particular to python, though python exercises (and python programmers?) do seem to talk an awful lot about language features this way. Jan 10, 2013 at 22:20
  • Another thought, is there something specific to python in the way it is willing to evaluate what looks like two "terms" just sitting adjacent to each other, the dict reference and the argument list? Do other languages allow that? It's sort of the programming equivalent of the leap in algebra from 5 * x to 5x (forgive the simple analogy). Jan 10, 2013 at 22:29
  • @mdeutschmtl: it's not really unique to Python, although languages which lack first class function or function object may never have any situations where a dictionary access immediately followed by function call could be possible.
    – Lie Ryan
    Jan 11, 2013 at 8:07
  • 4
    @mdeutschmtl "the fact that what you see on the surface is just a conventional way of presenting something much deeper." - that's called syntactic sugar and exists all over the place
    – Izkata
    May 13, 2014 at 3:35
7

There are 2 techniques that leap to my mind which you may be referring to, neither of which are Pythonic in that they are more broad than one language.

1. The technique of information hiding/encapsulation and cohesion (they usually go hand in hand so I'm lumping them together).

You have an object which has data, and you attaching a method (behavior) which is highly cohesive with the data. Should you need to change the function, extend the functionality or make any other changes the callers will not need to change (assuming no additional data needs to be passed in).

2. Dispatch tables

Not the classic case, because there is only one entry with a function. However, dispatch tables are used to organize different behaviors by a key such that they can looked up and called dynamically. I'm not sure if your thinking of this since your not referring to the function in a dynamic way, but none the less you still gain effective late binding (the "indirect" call).

Tradeoffs

One thing to note is what your doing will work fine with a known namespace of keys. However, you run the risk of collision between the data and the functions with an unknown namespace of keys.

1
  • Encapsulation because the data and the function stored in the dict(ionary) are related, and thus have cohesion. The data and function are from two very different dommains, so at first glance the example seems to be lumping wildly disparate entities together. May 14, 2014 at 14:07
0

I post this solution that I think is quite generic and can be useful as it is kept simple and easy to adapt to specific cases:

def p(what):
    print 'playing', cmpsr

def l(what):
    print 'listening', cmpsr

actions = {'Play' : p, 'Listen' : l}

act = 'Listen'
cmpsr = 'Vivaldi'

actions[act].__call__(cmpsr)

one can also define a list where each element is a function object and use the __call__ built in method. Credits to all for the inspiration and cooperation.

"The great artist is the simplifier", Henri Frederic Amiel

Not the answer you're looking for? Browse other questions tagged or ask your own question.