Recently, a colleague posted the following code snippet and asked for an explanation of why it didn’t work as they expected:
which results in:
instead of the expected:
The key is that the variable i is outside of the scope of the created lambda. Only the variable z is in the lambda scope. Essentially it would be like writing:
which makes it a lot more obvious what is going on. The global variable i is used each time the function is actually called–which is after the for loop is executed and i is now 9.
The fix is simple: make sure that i is in the scope of the function that is appended to array x.
Solution 1: using a closure
In this example, a closure around the function inner passes i into the returned function’s scope.
Solution 2: using lambda to create an anonymous closure
Here, we are appending the result of calling a lambda function with the argument i which returns a lambda that uses that value. This is exactly equivalent to the previous example, but for people who like one-liners. :)
Solution 3: using a lambda with a default argument
This solution ensures that we are using a variable n that is in the lambda’s scope and is initialized by default to i. A possible issue with this solution is if the caller of the function in x[i] passes an additional argument which overrides the default value of n. With the previous solutions, this bug would raise a TypeError exception instead of running successfully with (most likely) unintended results.