Home > Article > Backend Development > Scope analysis of closures and lambdas in Python
This article brings you relevant knowledge about Python, which mainly organizes related issues about the scope of lambda, as well as related content about closures in Python. Let’s take a look I hope it helps everyone.
【Related recommendations: Python3 video tutorial】
lambda Writing method
def fun(): for i in range(3): yield lambda x : x * i f0, f1, f2 = fun() print(f0(1), f1(2), f2(3))
Writing method of closure
def fun(): result = [] for i in range(3): def demo(x): return x * i result.append(demo) return result f0, f1, f2 = fun() print(f0(1), f1(2), f2(3))
The results of the above two writing methods are 2, 4, 6. According to the original idea, the results should be 0, 2, 6.
Cause of the problem:
The root of the problem lies in python’s variable search rules, LEGB (local, enclosed, global, bulitin). In the above example, i is in Closure scope (enclosing), and Python's closure is late binding. The value of the variable i used in the closure is found when the internal function is called.
Solution
Change closure scope to local scope
lambda writing method
def fun(): for i in range(3): yield lambda x, i = i: x * i f0, f1, f2 = fun() print(f0(1), f1(2), f2(3))
closure writing method
def fun(): result = [] for i in range(3): def demo(x, i=i): return x * i result.append(demo) return result f0, f1, f2 = fun() print(f0(1), f1(2), f2(3))
The above output result is 0, 2, 6
Another situation:
def fun(): for i in range(3): yield lambda x : x * i f0, f1, f2 = fun() print(f0(1), f1(2), f2(3))
The output result is still 2, 4, 6
Cause of the problem
The generator (or iterator) returned by the fun() method is not actually executed, but is executed every time it is called.
When printing is performed after traversal, the i variable uses the value of the last call. If lambda is regarded as a closure method, the value of variable i is still in the closure scope (no local)
def create(): return [lambda x:i*x for i in range(5)] for i in create(): print(i(2))
Result:
8
8
8
8
8
The return value of the create function is a list, and each element of the list is a function - a function that multiplies the input parameter x by a multiple i. The expected results were 0, 2, 4, 6, 8. But the result was 5 and 8, which was unexpected.
Since lambda is often used when this trap occurs, you may think it is a problem with lambda, but lambda expresses its unwillingness to take the blame. The essence of the problem lies in the attribute search rules in python, LEGB (local, enclosing, global, bulitin). In the above example, i is in the closure scope (enclosing), and Python's closure is late binding. This means that the value of the variable used in the closure is queried when the internal function is called.
The solution is also very simple, that is, change the closure scope to the local scope.
def create(): return [lambda x, i=i:i*x for i in range(5)] for i in create(): print(i(2))
Another way of writing:
def create(): a = [] for i in range(5): def demo(x, i=i): return x*i a.append(demo) return a for i in create(): print(i(2))
The above two ways of writing are the same
Result:
0
2
4
6
8
Another chestnut with a similar problem
The code is very simple: (Statement: python3 Question)
nums = range(2,20) for i in nums: nums = filter(lambda x: x==i or x%i, nums) print(list(nums))
Result:
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 , 17, 18, 19]
Similarly, according to normal logic, the result should be:
[2, 3, 5, 7, 11, 13, 17, 19 ]
Cause of the problem:
Modify code:
nums = range(2,20) for i in nums: nums = filter(lambda x,i=i: x==i or x%i, nums) print(list(nums))
Result:
[2, 3, 5, 7, 11, 13, 17, 19]
【 Related recommendations: Python3 video tutorial】
The above is the detailed content of Scope analysis of closures and lambdas in Python. For more information, please follow other related articles on the PHP Chinese website!