Scope analysis of closures and lambdas in Python

WBOY
Release: 2022-07-22 19:53:30
forward
2564 people have browsed it

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.

Scope analysis of closures and lambdas in Python

【Related recommendations: Python3 video tutorial

Scope of Python closures and lambda

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))
Copy after login

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))
Copy after login

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))
Copy after login

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))
Copy after login

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))
Copy after login

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)

The pitfalls in python (closure and lambda)

Let’s look at a chestnut first

def create():
    return [lambda x:i*x for i in range(5)]
 
for i in create():
    print(i(2))
Copy after login

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))
Copy after login

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))
Copy after login

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))
Copy after login

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:

  • In python3, the filter() function returns an iterator, so it does not actually do any Executed, but executed every time it is called (the value list returned by filter() in python2 does not have this phenomenon)
  • When printing is executed after traversal, the function in the loop is now executed, the same as the chestnut above The problem is that the variable i uses the value of the last call. The difference from the above chestnut is that the above chestnut uses the value of the embedded scope, while this chestnut uses the value of the global i

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))
Copy after login

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!

Related labels:
source:jb51.net
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template