Lambda Function Don't Closure the Parameter in Python

What do lambda function closures capture?

What do the closures capture exactly?

Closures in Python use lexical scoping: they remember the name and scope of the closed-over variable where it is created. However, they are still late binding: the name is looked up when the code in the closure is used, not when the closure is created. 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.

There are at least two ways to get early binding instead:

  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. More verbosely but also more robustly, we can create a new scope for each created 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 (another 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 + x
    adders = [createAdder(i) for i in range(4)]

Python lambda's binding to local values

Change x.append(lambda : pv(v)) to x.append(lambda v=v: pv(v)).

You expect "python lambdas to bind to the reference a local variable is pointing to, behind the scene", but that is not how Python works. Python looks up the variable name at the time the function is called, not when it is created. Using a default argument works because default arguments are evaluated when the function is created, not when it is called.

This is not something special about lambdas. Consider:

x = "before foo defined"
def foo():
print x
x = "after foo was defined"
foo()

prints

after foo was defined

Python lambda closure scoping

The reason is that closures (lambdas or otherwise) close over names, not values. When you define lambda x: test_fun(n, x), the n is not evaluated, because it is inside the function. It is evaluated when the function is called, at which time the value that is there is the last value from the loop.

You say at the beginning that you want to "use closures to eliminate a variable from a function signature", but it doesn't really work that way. (See below, though, for a way that may satisfy you, depending on what you mean by "eliminate".) Variables inside the function body will not be evaluated when the function is defined. In order to get the function to take a "snapshot" of the variable as it exists at function-definition time, you must pass the variable as an argument. The usual way to do this is to give the function an argument whose default value is the variable from the outer scope. Look at the difference between these two examples:

>>> stuff = [lambda x: n+x for n in [1, 2, 3]]
>>> for f in stuff:
... print f(1)
4
4
4
>>> stuff = [lambda x, n=n: n+x for n in [1, 2, 3]]
>>> for f in stuff:
... print f(1)
2
3
4

In the second example, passing n as an argument to the function "locks in" the current value of n to that function. You have to do something like this if you want to lock in the value in this way. (If it didn't work this way, things like global variables wouldn't work at all; it's essential that free variables be looked up at the time of use.)

Note that nothing about this behavior is specific to lambdas. The same scoping rules are in effect if you use def to define a function that references variables from the enclosing scope.

If you really want to, you can avoid adding the extra argument to your returned function, but to do so you must wrap that function in yet another function, like so:

>>> def makeFunc(n):
... return lambda x: x+n
>>> stuff = [makeFunc(n) for n in [1, 2, 3]]
>>> for f in stuff:
... print f(1)
2
3
4

Here, the inner lambda still looks up the value of n when it is called. But the n it refers to is no longer a global variable but a local variable inside the enclosing function makeFunc. A new value of this local variable is created every time makeFunc is called, and the returned lambda creates a closure that "saves" the local variable value that was in effect for that invocation of makeFunc. Thus each function created in the loop has its own "private" variable called x. (For this simple case, this can also be done using a lambda for the outer function --- stuff = [(lambda n: lambda x: x+n)(n) for n in [1, 2, 3]] --- but this is less readable.)

Notice that you still have to pass your n as an argument, it's just that, by doing it this way, you don't pass it as an argument to the same function that winds up going into the stuff list; instead you pass it as an argument to a helper function that creates the function you want to put into stuff. The advantage of using this two-function approach is that the returned function is "clean" and doesn't have the extra argument; this could be useful if you were wrapping functions that accepted a lot of arguments, in which case it could become confusing to remember where the n argument was in the list. The disadvantage is that, doing it this way, the process of making the functions is more complicated, since you need another enclosing function.

The upshot is that there is a tradeoff: you can make the function-creation process simpler (i.e., no need for two nested functions), but then you must make the resulting function a bit more complicated (i.e., it has this extra n=n argument). Or you can make the function simpler (i.e., it has no n=n argument), but then you must make the function-creation process more complicated (i.e., you need two nested functions to implement the mechanism).

What is the difference between a 'closure' and a 'lambda'?

A lambda is just an anonymous function - a function defined with no name. In some languages, such as Scheme, they are equivalent to named functions. In fact, the function definition is re-written as binding a lambda to a variable internally. In other languages, like Python, there are some (rather needless) distinctions between them, but they behave the same way otherwise.

A closure is any function which closes over the environment in which it was defined. This means that it can access variables not in its parameter list. Examples:

def func(): return h
def anotherfunc(h):
return func()

This will cause an error, because func does not close over the environment in anotherfunc - h is undefined. func only closes over the global environment. This will work:

def anotherfunc(h):
def func(): return h
return func()

Because here, func is defined in anotherfunc, and in python 2.3 and greater (or some number like this) when they almost got closures correct (mutation still doesn't work), this means that it closes over anotherfunc's environment and can access variables inside of it. In Python 3.1+, mutation works too when using the nonlocal keyword.

Another important point - func will continue to close over anotherfunc's environment even when it's no longer being evaluated in anotherfunc. This code will also work:

def anotherfunc(h):
def func(): return h
return func

print anotherfunc(10)()

This will print 10.

This, as you notice, has nothing to do with lambdas - they are two different (although related) concepts.

Python closure not working as expected

One way is to do this:

def main():
files = [r'C:\_local\test.txt', r'C:\_local\junk.txt']
funcs = []
for f in files:
# create a new lambda and store the current `f` as default to `path`
funcs.append(lambda path=f: os.stat(path))
print funcs

# calling the lambda without a parameter uses the default value
funcs[0]()
funcs[1]()

Otherwise f is looked up when the function is called, so you get the current (after the loop) value.

Ways I like better:

def make_statfunc(f):
return lambda: os.stat(f)

for f in files:
# pass the current f to another function
funcs.append(make_statfunc(f))

or even (in python 2.5+):

from functools import partial
for f in files:
# create a partially applied function
funcs.append(partial(os.stat, f))

Python lambda function is not being called correctly from within a for loop

This is a classic case of unwanted closure. Here's a simplified example:

funcs = []
for i in range(3):
funcs.append(lambda: i + 1)
for func in funcs:
print(func())

One might expect that this will print 1 2 3, but it prints 3 3 3 instead. The reason is, lambda is a closure, closing over the variable i (capturing it in its context). When we execute the functions, the variable i is left at its last value in the loop (2). To reiterate, the lambda does not capture the value, but the variable. To avoid this, we want to pass the current value of i into the function as a parameter. To do that, we can construct a function that accepts i as the parameter, captures the parameter into the closure and returns the "customised" function we want:

from functools import partial
funcs = []
for i in range(3):
funcs.append((lambda val: lambda: val + 1)(i))
for func in funcs:
print(func())

Equivalently, we can use functools.partial, which does just this:

from functools import partial
funcs = []
for i in range(3):
funcs.append(partial(lambda val: val + 1, i))
for func in funcs:
print(func())

Here, lambda val: val + 1 will expect a parameter; partial(lambda val: val + 1, 0) will produce a new function where the first parameter is fixed at 0 - basically, lambda: 0 + 1. This captures no variables, and thus avoids the problem you encountered.

tl;dr:

command=partial(lambda i: self.process(charOrder[i]), imgIndex)

Scope of lambda functions and their parameters?

The problem here is the m variable (a reference) being taken from the surrounding scope.
Only parameters are held in the lambda scope.

To solve this you have to create another scope for lambda:

def callback(msg):
print msg

def callback_factory(m):
return lambda: callback(m)

funcList=[]
for m in ('do', 're', 'mi'):
funcList.append(callback_factory(m))
for f in funcList:
f()

In the example above, lambda also uses the surounding scope to find m, but this
time it's callback_factory scope which is created once per every callback_factory
call.

Or with functools.partial:

from functools import partial

def callback(msg):
print msg

funcList=[partial(callback, m) for m in ('do', 're', 'mi')]
for f in funcList:
f()

How to define lambda functions to override several slots in Qt?

Ok,

I got it:

I just defined input attributes passed to the lambda:

slotLambda = lambda lightType=lightType, param=param, lightTypeBox=lightTypeBox: self.updateLighting(lightType, param, lightTypeBox.isChecked())

So every lambda has its own arguments :-).



Related Topics



Leave a reply



Submit