Function definition in a for loop using local variable
Question:
I’m at a loss here.
I’m trying to define a function inside a for loop. The function uses a variable defined inside the loop and could look something similar like that :
myFuns = []
for i in range(10):
j = i + 4
def fun(): print(j)
myFuns += [fun]
At the end of this loop, my functions in myFuns are differents, but they do the same thing, as apparently, this is not a new variable j that is passed to fun(), but the reference of j.
I’d be very glad to know how to pass the value of j and not just the reference.
I didn’t know that a variable created in a loop could outlived the loop, so this is new territory for me here…
Answers:
j
is a free variable, whose value is looked up when fun
is called; fun
does not bake the current value of j
into its definition. Further, lacking any other containing scope, the call to fun
will refer to j
in the global scope, where its last set value was its value in the last iteration of the loop.
To actually store a fixed value for j
in fun
when it is defined, you would need to pass it as a parameter with a default value:
myFuns = []
for i in range(10):
j = i + 4
def fun(j=j):
print(j)
myFuns.append(fun) # Don't use += [...] for a single item
However, a closure may be more appropriate:
# Here, j is a free variable in _, but its value comes from the local
# variable j defined by make_fun, not the global scope.
def make_fun(j):
def _():
return j
return _
myFuns = [make_fun(i) for i in range(10)]
I’m at a loss here.
I’m trying to define a function inside a for loop. The function uses a variable defined inside the loop and could look something similar like that :
myFuns = []
for i in range(10):
j = i + 4
def fun(): print(j)
myFuns += [fun]
At the end of this loop, my functions in myFuns are differents, but they do the same thing, as apparently, this is not a new variable j that is passed to fun(), but the reference of j.
I’d be very glad to know how to pass the value of j and not just the reference.
I didn’t know that a variable created in a loop could outlived the loop, so this is new territory for me here…
j
is a free variable, whose value is looked up when fun
is called; fun
does not bake the current value of j
into its definition. Further, lacking any other containing scope, the call to fun
will refer to j
in the global scope, where its last set value was its value in the last iteration of the loop.
To actually store a fixed value for j
in fun
when it is defined, you would need to pass it as a parameter with a default value:
myFuns = []
for i in range(10):
j = i + 4
def fun(j=j):
print(j)
myFuns.append(fun) # Don't use += [...] for a single item
However, a closure may be more appropriate:
# Here, j is a free variable in _, but its value comes from the local
# variable j defined by make_fun, not the global scope.
def make_fun(j):
def _():
return j
return _
myFuns = [make_fun(i) for i in range(10)]