Home  >  Article  >  Backend Development  >  Scope analysis of closures and lambdas in Python

Scope analysis of closures and lambdas in Python

WBOY
WBOYforward
2022-07-22 16:37:122572browse

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))

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)

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))

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:

  • 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))

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!

Statement:
This article is reproduced at:jb51.net. If there is any infringement, please contact admin@php.cn delete