I'm currently learning about closure and this code was presented:
def outer_func(x):
y = 4
def inner_func(z):
print(f"x = {x}, y = {y}, z = {z}")
return x y z
return inner_func
for i in range(3):
closure = outer_func(i)
print(f"closure({i 5}) = {closure(i 5)}")
I understand x
is defined at the point outer_func
is assigned to closure
, and y
is defined within the function each time. My question is how is z
defined? Shouldn't the call to closure
overwrite the value of x
? How does python know to assign this new value to z
?
CodePudding user response:
My question is how is
z
defined?
z
is a parameter of inner_func
. It means it's always local to the inner_func
function(local variable). When the outer_func
function is called the body of it will be executed, which indeed first create inner_func
and give you back a reference to it. Then whatever you pass to inner_func
, it uses as the z
. It's a normal argument passing.
Shouldn't the call to closure overwrite the value of
x
?
inner_func
is your closure. It has access to it's enclosing scope which is outer_func
. x
is a parameter of outer_func
, it gets it's value from executing the line:
closure = outer_func(i)
So whatever you pass to outer_func
becomes available to the inner_func
's body. (Closure mechanism)
How does python know to assign this new value to z?
I already answered this in the first part. In the line:
print(f"closure({i 5}) = {closure(i 5)}")
you are passing the value of z
in closure(i 5)
part.
Q: Now where does inner_func
get y
's value from? A: Again it's a closure, it has access to outer_func
namespace. y
is always defined when outer_func()
is called. Nothing can change it's value in your code. That loop can only change x
because it comes from outside. (argument)
CodePudding user response:
Your question is:
I understand x is defined at the point outer_func is assigned to closure, and y is defined within the function each time. My question is how is z defined? Shouldn't the call to closure overwrite the value of x? How does python know to assign this new value to z?
Your code is:
def outer_func(x):
y = 4
def inner_func(z):
print(f"x = {x}, y = {y}, z = {z}")
return x y z
return inner_func
for i in range(3):
closure = outer_func(i)
print(f"closure({i 5}) = {closure(i 5)}")
The call to closure
is effectively a call to inner_func
(not outer_func
) and the argument passed to closure
will be assigned to z
(not x
).
Explanation:
Each execution of closure = outer_func(i)
does the following:
- call
outer_func()
thereby effectively assigning the passed argumenti
to the variablex
in the scope ofouter_func()
- execute
y = 4
- leave
outer_func()
with a return value of type function whose value isinner_func
- assign the return value of
outer_func()
(namely the functioninner_func
) toclosure
, with ongoing access to the variables in the containing scope ofinner_func()
(namely, the scope ofouter_func()
).
Each call to closure()
within the for
loop does the following:
- call
inner_func()
thereby assigning the passed argument toz
in the scope ofinner_func()
- execute the body of
inner_func()
wherex
andy
have the values they had at the time of the call toouter_func()
that created this copy ofinner_func
as a closure.