A closure in Python captures free variables , not their current values, at the time the closure was created. For instance:
def make_closures(): L = []
30, 10, 40, 20 will be displayed: this is because the first pair of closures pushA , popA will refer to one list L , and the second pair of pushB , popB will refer to another independent list.
The important point is that in each pair of push and pop closures refer to the same list, i.e. they capture the variable L , not the value of L at creation time. If L mutated by one closure, then others will see changes.
One common mistake, for example, is to expect that
L = [] for i in range(10): L.append(lambda : i) for x in L: print(x())
displays numbers from 0 to 9 ... all unnamed closures here fix the same variable i that is used for the loop, and they all return the same value when called.
The general Python idiom to solve this problem is
L.append(lambda i=i: i)
i.e. using the fact that the default values ββfor parameters are evaluated at the time the function is created. With this approach, each closure returns a different value, because they return their private local variable (a parameter that has a default value).
source share