Question
Asked By – sharvey
I’m trying to create functions inside of a loop:
functions = []
for i in range(3):
def f():
return i
# alternatively: f = lambda: i
functions.append(f)
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?
Now we will see solution for issue: Creating functions (or lambdas) in a loop (or comprehension)
Answer
You’re running into a problem with late binding — each function looks up i
as late as possible (thus, when called after the end of the loop, i
will be set to 2
).
Easily fixed by forcing early binding: change def f():
to def f(i=i):
like this:
def f(i=i):
return i
Default values (the right-hand i
in i=i
is a default value for argument name i
, which is the left-hand i
in i=i
) are looked up at def
time, not at call
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”:
def make_f(i):
def f():
return i
return f
and in your loop use f = make_f(i)
instead of the def
statement.
This question is answered By – Alex Martelli
This answer is collected from stackoverflow and reviewed by FixPython community admins, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0