What do (lambda) function closures capture? What do (lambda) function closures capture? python python

What do (lambda) function closures capture?

you may force the capture of a variable using an argument with a default value:

>>> for i in [0,1,2,3]:...    adders[i]=lambda a,i=i: i+a  # note the dummy parameter with a default value...>>> print( adders[1](3) )4

the idea is to declare a parameter (cleverly named i) and give it a default value of the variable you want to capture (the value of i)

Your second question has been answered, but as for your first:

what does the closure capture exactly?

Scoping in Python is dynamic and lexical. A closure will always remember the name and scope of the variable, not the object it's pointing to. Since all the functions in your example are created in the same scope and use the same variable name, they always refer to the same variable.

EDIT: Regarding your other question of how to overcome this, there are two ways that come to mind:

  1. The most concise, but not strictly equivalent way is the one recommended by Adrien Plisson. Create a lambda with an extra argument, and set the extra argument's default value to the object you want preserved.

  2. A little more verbose but less hacky would be to create a new scope each time you create the lambda:

    >>> adders = [0,1,2,3]>>> for i in [0,1,2,3]:...     adders[i] = (lambda b: lambda a: b + a)(i)...     >>> adders[1](3)4>>> adders[2](3)5

    The scope here is created using a new function (a lambda, for brevity), which binds its argument, and passing the value you want to bind as the argument. In real code, though, you most likely will have an ordinary function instead of the lambda to create the new scope:

    def createAdder(x):    return lambda y: y + xadders = [createAdder(i) for i in range(4)]

For completeness another answer to your second question: You could use partial in the functools module.

With importing add from operator as Chris Lutz proposed the example becomes:

from functools import partialfrom operator import add   # add(a, b) -- Same as a + b.adders = [0,1,2,3]for i in [0,1,2,3]:   # store callable object with first argument given as (current) i   adders[i] = partial(add, i) print adders[1](3)