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
zdefined?
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 argumentito the variablexin 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 tozin the scope ofinner_func() - execute the body of
inner_func()wherexandyhave the values they had at the time of the call toouter_func()that created this copy ofinner_funcas a closure.
