I'm trying to create functions inside of a loop and storing them in a dictionary. The problem is that all entries in the dictionary seem end up mapping to the last created function. The code goes like this:
d = {}
def test(**kwargs):
for k in kwargs:
def f():
print(k, kwargs[k])
d[k] = f
f()
test(foo=1, bar=2)
print('should print the same output as before')
d['foo']()
d['bar']()
This outputs:
foo 1
bar 2
should print the same output as before
bar 2
bar 2
Any idea why?
You're running into a problem with late binding -- each function looks up
k
as late as possible (thus, when called outsidetest
, this happens after the end of the loop).Easily fixed by forcing early binding: change
def f():
todef f(k=k):
like this:Default values (the right-hand
k
ink=k
is a default value for argument namek
, which is the left-handk
ink=k
) are looked up atdef
time, not atcall
time, so essentially they're a way to specifically looking for early binding.If you're worried about
f
getting an extra argument (and thus potentially being called erroneously), there's a more sophisticated way which involved using a closure as a "function factory":and in your loop use
f = make_f(kwargs, k)
instead of thedef
statement.