Defining a python dictionary of lambdas through a for cycle
The reason it doesn't work has to do with late-binding closures in Python.
Python’s closures are late binding. This means that the values of variables used in closures are looked up at the time the inner function is called.
Adapting the source explanation, whenever the return function is called, the value of key
is looked up in the surrounding scope at call time. By then, the loop has completed and key
is left with its final value of 'foo'
.
You can resolve this by creating a closure that binds immediately to its arguments by using a default arg like so:
a = {'bar': 0, 'foo': 1} # a reference dictionary
dic1 = {'bar': lambda x: x['bar'], 'foo': lambda x: x['foo']}
dic2 = {key: lambda x, key=key: x[key] for key in a}
print(dic1['bar'](a), dic1['foo'](a))
print(dic2['bar'](a), dic2['foo'](a))
Result:
0 1
0 1
One simple way to do that is with operator.itemgetter
:
from operator import itemgetter
a = {'bar': 0, 'foo': 1}
dic1 = {key: itemgetter(key) for key in a}
print(dic1['bar'](a), dic1['foo'](a))
# 0 1
Alternatively, you need to bind each value of key
to each dictionary value, typically you do that with something like this:
a = {'bar': 0, 'foo': 1}
dic1 = {key: (lambda key: lambda x: x[key])(key) for key in a}
print(dic1['bar'](a), dic1['foo'](a))
# 0 1