Encapsulating variables within closures to remove them from function signatures is a technique often used for efficient code structuring. However, in the case of non-nested lambdas, the closure retains the final value of the variable, leading to issues when attempting to access specific values based on the iterating variable.
Consider the provided code snippet:
names = ['a', 'b', 'c'] def test_fun(name, x): print(name, x) def gen_clousure(name): return lambda x: test_fun(name, x) funcs1 = [gen_clousure(n) for n in names] funcs2 = [lambda x: test_fun(n, x) for n in names] # Expected output for funcs1 for f in funcs1: f(1) # Unexpected output for funcs2 (returns last element for all cases) for f in funcs2: f(1)
Understanding the reason behind this discrepancy is crucial for effective closure utilization.
The fundamental concept in this situation is variable scoping in closures. Closures inherently hold the variable names rather than their values. This means that the variable's evaluation occurs when the lambda execution initiates, rather than at the time of lambda definition.
In the case of funcs2, when you execute lambda x: test_fun(n, x), the variable n is not assessed during lambda definition. Instead, the evaluation only happens upon the lambda call. At that point, n holds the last value from the loop (which is 'c' in this instance). Consequently, the function f always utilizes 'c' as the value of n, regardless of the input x.
To address this issue and achieve the desired functionality, the variable n must be captured in the lambda function's scope. This can be achieved by passing the variable as an argument to the lambda, as showcased in the following:
funcs2 = [lambda x: test_fun(n, x) for n in names if 2 > 0]
By including this additional if-statement that always holds true, we force the lambda to take the value of n as an argument, ensuring the expected personalized behaviour across all cases.
Alternatively, you can wrap the non-nested lambda in a nested function, effectively preventing the access to undeclared variables in the scope. The following code illustrates this approach:
def makeFunc(n): return lambda x: x n stuff = [makeFunc(n) for n in [1, 2, 3]] for f in stuff: print(f(1))
Here, the variable n is captured in the function makeFunc, ensuring proper scoping within the lambda.
Understanding and managing variable scoping in closures is essential for effective code design and debugging. The key takeaways are:
Disclaimer: All resources provided are partly from the Internet. If there is any infringement of your copyright or other rights and interests, please explain the detailed reasons and provide proof of copyright or rights and interests and then send it to the email: [email protected] We will handle it for you as soon as possible.
Copyright© 2022 湘ICP备2022001581号-3