Why store a function inside a python dictionary?

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

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

@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

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

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

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

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật