Parameterized functions of no arguments?

Steven D'Aprano steve+comp.lang.python at pearwood.info
Fri Feb 11 03:19:00 EST 2011


On Fri, 11 Feb 2011 06:32:56 +0000, Rotwang wrote:

> I don't understand why this works. What is the difference between
> 
>      (lambda x: lambda: f(x))(k)
> 
> and
> 
>      lambda: f(k)
> 
> ?

Re-writing them as normal function defs may help. I'm going to do them in 
reverse order:

# lambda: f(k)
def func():
    return f(k)

When you call func() with no arguments, the body is executed and f(k) is 
returned. Where do f and k come from? At runtime, Python searches the 
local namespace of func(), and doesn't find either f or k. It then 
searches the non-local namespace, that is, the function or method that 
surrounds func (or your lambda), if any. In your case, there is no such 
nested function, so finally it searches the global namespace, and finds 
both f and k. But by the time the function is called, the for-loop which 
sets k has reached the end, and k always has the same value.



# (lambda x: lambda: f(x))(k)
def func(x):
    def inner():
        return f(x)
    return inner


When you call func(k), it creates a nested function. That nested function 
includes a "closure", which is a copy of the namespace of func at the 
time it is called. This closure includes a variable "k".

That inner function is returned and saved as the callback function. When 
you call that callback function, it executes inner(), and f(k) is 
returned. Where do f and k come from? As normal, Python searches the 
local namespace, and doesn't find them, but then it finds the variable k 
in the closure, and *not* the global k that the earlier example would 
find.

This example may help:

store = []
for k in range(3):
    fa = lambda: "k has the value %d" % k
    fb = (lambda x: lambda: "x has the value %d" % x)(k)
    print("fa inside the loop", fa())
    print("fb inside the loop", fb())
    store.append(fa)
    store.append(fb)

for func in store:
    print("func outside the loop", func())

del k

store[1]()  # one of the closures
store[0]()  # one of the non-closures




Hope this helps.


-- 
Steven



More information about the Python-list mailing list