I’m trying to create functions inside of a loop:
functions = []
for i in range(3):
def f():
return i
functions.append(f)
Alternatively, with lambda:
functions = []
for i in range(3):
functions.append(lambda: i)
The problem is that all functions end up being the same. Instead of returning 0, 1, and 2, all three functions return 2:
print([f() for f in functions])
- Expected output:
[0, 1, 2] - Actual output:
[2, 2, 2]
Why is this happening, and what should I do to get 3 different functions that output 0, 1, and 2 respectively?
You’re running into a problem with late binding — each function looks up
ias late as possible (thus, when called after the end of the loop,iwill be set to2).Easily fixed by forcing early binding: change
def f():todef f(i=i):like this:Default values (the right-hand
iini=iis a default value for argument namei, which is the left-handiini=i) are looked up atdeftime, not atcalltime, so essentially they’re a way to specifically looking for early binding.If you’re worried about
fgetting 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(i)instead of thedefstatement.