I’m trying to implement a closure in Python 2.6 and I need to access a nonlocal variable but it seems like this keyword is not available in python 2.x. How should one access nonlocal variables in closures in these versions of python?
Inner functions can read nonlocal variables in 2.x, just not rebind them. This is annoying, but you can work around it. Just create a dictionary, and store your data as elements therein. Inner functions are not prohibited from mutating the objects that nonlocal variables refer to.
The following solution is inspired by the answer by Elias Zamaria, but contrary to that answer does handle multiple calls of the outer function correctly. The “variable” inner.y is local to the current call of outer. Only it isn’t a variable, since that is forbidden, but an object attribute (the object being the function inner itself). This is very ugly (note that the attribute can only be created after the inner function is defined) but seems effective.
I think the key here is what you mean by “access”. There should be no issue with reading a variable outside of the closure scope, e.g.,
x = 3
def outer():
def inner():
print x
inner()
outer()
should work as expected (printing 3). However, overriding the value of x does not work, e.g.,
x = 3
def outer():
def inner():
x = 5
inner()
outer()
print x
will still print 3. From my understanding of PEP-3104 this is what the nonlocal keyword is meant to cover. As mentioned in the PEP, you can use a class to accomplish the same thing (kind of messy):
It is redundant to use the name of the function in the assignment statement of the variable, but it looks simpler and cleaner to me than putting the variable in a dictionary. The value is remembered from one call to another, just like in Chris B.’s answer.
After looking back at this recently, I was struck by how decorator-like it was—when it dawned on me that implementing it as one would make it more generic & useful (although doing so arguably degrades its readability to some degree).
# Implemented as a decorator.
class Nonlocal(object):
""" Decorator class to help implement nonlocal names in Python 2.x """
def __init__(self, **kwargs):
self._vars = kwargs
def __call__(self, func):
for k, v in self._vars.items():
setattr(func, k, v)
return func
@Nonlocal(y=0)
def outer():
def inner():
outer.y += 1
return outer.y
return inner
f = outer()
print(f(), f(), f()) # -> (1 2 3)
Note that both versions work in both Python 2 and 3.
There is a wart in python’s scoping rules – assignment makes a variable local to its immediately enclosing function scope. For a global variable, you would solve this with the global keyword.
The solution is to introduce an object which is shared between the two scopes, which contains mutable variables, but is itself referenced through a variable which is not assigned.
You might be able to figure out some trickery to get the name of the parameter to outer, and then pass it as varname, but without relying on the name outer you would like need to use a Y combinator.
回答 7
另一种方法(尽管太冗长了):
import ctypes
def outer():
y =0def inner():
ctypes.pythonapi.PyCell_Set(id(inner.func_closure[0]), id(y +1))return y
return inner
x = outer()
x()>>1
x()>>2
y = outer()
y()>>1
x()>>3
Extending Martineau elegant solution above to a practical and somewhat less elegant use case I get:
class nonlocals(object):
""" Helper to implement nonlocal names in Python 2.x.
Usage example:
def outer():
nl = nonlocals( n=0, m=1 )
def inner():
nl.n += 1
inner() # will increment nl.n
or...
sums = nonlocals( { k:v for k,v in locals().iteritems() if k.startswith('tot_') } )
"""
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
def __init__(self, a_dict):
self.__dict__.update(a_dict)
回答 9
使用全局变量
def outer():global y # import1
y =0def inner():global y # import2 - requires import1
y +=1return y
return inner
f = outer()print(f(), f(), f())#prints 1 2 3
def outer():
global y # import1
y = 0
def inner():
global y # import2 - requires import1
y += 1
return y
return inner
f = outer()
print(f(), f(), f()) #prints 1 2 3
where user needs to declare a global variable ranks, every time you need to call the report. My improvement eliminates the need to initialize the function variables from the user.
Okay, bear with me on this, I know it’s going to look horribly convoluted, but please help me understand what’s happening.
from functools import partial
class Cage(object):
def __init__(self, animal):
self.animal = animal
def gotimes(do_the_petting):
do_the_petting()
def get_petters():
for animal in ['cow', 'dog', 'cat']:
cage = Cage(animal)
def pet_function():
print "Mary pets the " + cage.animal + "."
yield (animal, partial(gotimes, pet_function))
funs = list(get_petters())
for name, f in funs:
print name + ":",
f()
Gives:
cow: Mary pets the cat.
dog: Mary pets the cat.
cat: Mary pets the cat.
So basically, why am I not getting three different animals? Isn’t the cage ‘packaged’ into the local scope of the nested function? If not, how does a call to the nested function look up the local variables?
I know that running into these kind of problems usually means one is ‘doing it wrong’, but I’d like to understand what happens.
The nested function looks up variables from the parent scope when executed, not when defined.
The function body is compiled, and the ‘free’ variables (not defined in the function itself by assignment), are verified, then bound as closure cells to the function, with the code using an index to reference each cell. pet_function thus has one free variable (cage) which is then referenced via a closure cell, index 0. The closure itself points to the local variable cage in the get_petters function.
When you actually call the function, that closure is then used to look at the value of cage in the surrounding scope at the time you call the function. Here lies the problem. By the time you call your functions, the get_petters function is already done computing it’s results. The cage local variable at some point during that execution was assigned each of the 'cow', 'dog', and 'cat' strings, but at the end of the function, cage contains that last value 'cat'. Thus, when you call each of the dynamically returned functions, you get the value 'cat' printed.
The work-around is to not rely on closures. You can use a partial function instead, create a new function scope, or bind the variable as a default value for a keyword parameter.
after iterating the value of i is lazily stored as its final value.
As a generator the function would work (i.e. printing each value in turn), but when transforming to a list it runs over the generator, hence all calls to cage (cage.animal) return cats.
>>> list(get_petters())[('cow',<function get_petters.<locals>.pet_function at 0x7ff2b988d790>),('dog',<function get_petters.<locals>.pet_function at 0x7ff2c18f51f0>),('cat',<function get_petters.<locals>.pet_function at 0x7ff2c14a9f70>)]
但是,请看一下cell这些函数绑定到的:
>>>for _, f in list(get_petters()):...print(f(), f.__closure__)Mary pets the cat.(<cell at 0x7ff2c112a9d0: str object at 0x7ff2c3f437f0>,)Mary pets the cat.(<cell at 0x7ff2c112a9d0: str object at 0x7ff2c3f437f0>,)Mary pets the cat.(<cell at 0x7ff2c112a9d0: str object at 0x7ff2c3f437f0>,)>>>for _, f in get_petters():...print(f(), f.__closure__)Mary pets the cow.(<cell at 0x7ff2b86b5d00: str object at 0x7ff2c1a95670>,)Mary pets the dog.(<cell at 0x7ff2b86b5d00: str object at 0x7ff2c1a952f0>,)Mary pets the cat.(<cell at 0x7ff2b86b5d00: str object at 0x7ff2c3f437f0>,)
def get_petters():
for animal in ['cow', 'dog', 'cat']:
def pet_function():
return "Mary pets the " + animal + "."
yield (animal, pet_function)
Then, just like in the question, we get:
>>> for name, f in list(get_petters()):
... print(name + ":", f())
cow: Mary pets the cat.
dog: Mary pets the cat.
cat: Mary pets the cat.
But if we avoid creating a list() first:
>>> for name, f in get_petters():
... print(name + ":", f())
cow: Mary pets the cow.
dog: Mary pets the dog.
cat: Mary pets the cat.
What’s going on? Why does this subtle difference completely change our results?
If we look at list(get_petters()), it’s clear from the changing memory addresses that we do indeed yield three different functions:
>>> list(get_petters())
[('cow', <function get_petters.<locals>.pet_function at 0x7ff2b988d790>),
('dog', <function get_petters.<locals>.pet_function at 0x7ff2c18f51f0>),
('cat', <function get_petters.<locals>.pet_function at 0x7ff2c14a9f70>)]
However, take a look at the cells that these functions are bound to:
>>> for _, f in list(get_petters()):
... print(f(), f.__closure__)
Mary pets the cat. (<cell at 0x7ff2c112a9d0: str object at 0x7ff2c3f437f0>,)
Mary pets the cat. (<cell at 0x7ff2c112a9d0: str object at 0x7ff2c3f437f0>,)
Mary pets the cat. (<cell at 0x7ff2c112a9d0: str object at 0x7ff2c3f437f0>,)
>>> for _, f in get_petters():
... print(f(), f.__closure__)
Mary pets the cow. (<cell at 0x7ff2b86b5d00: str object at 0x7ff2c1a95670>,)
Mary pets the dog. (<cell at 0x7ff2b86b5d00: str object at 0x7ff2c1a952f0>,)
Mary pets the cat. (<cell at 0x7ff2b86b5d00: str object at 0x7ff2c3f437f0>,)
For both loops, the cell object remains the same throughout the iterations. However, as expected, the specific str it references varies in the second loop. The cell object refers to animal, which is created when get_petters() is called. However, animal changes what str object it refers to as the generator function runs.
In the first loop, during each iteration, we create all the fs, but we only call them after the generator get_petters() is completely exhausted and a list of functions is already created.
In the second loop, during each iteration, we are pausing the get_petters() generator and calling f after each pause. Thus, we end up retrieving the value of animal at that moment in time that the generator function is paused.
Three separate functions are created, but they each have the closure of the environment they’re defined in – in this case, the global environment (or the outer function’s environment if the loop is placed inside another function). This is exactly the problem, though — in this environment, animal is mutated, and the closures all refer to the same animal.
my @flist=();
foreach my $i (0..2){
push(@flist, sub {$i * $_[0]});}
foreach my $f (@flist){print $f->(2),"\n";}
打印“ 0 2 4”。
你能解释一下区别吗?
更新:
这个问题是不是与i是全球性的。这显示相同的行为:
flist =[]def outer():for i in xrange(3):def inner(x):return x * i
flist.append(inner)
outer()#~ print i # commented because it causes an errorfor f in flist:print f(2)
While I was investigating a problem I had with lexical closures in Javascript code, I came along this problem in Python:
flist = []
for i in xrange(3):
def func(x): return x * i
flist.append(func)
for f in flist:
print f(2)
Note that this example mindfully avoids lambda. It prints “4 4 4”, which is surprising. I’d expect “0 2 4”.
This equivalent Perl code does it right:
my @flist = ();
foreach my $i (0 .. 2)
{
push(@flist, sub {$i * $_[0]});
}
foreach my $f (@flist)
{
print $f->(2), "\n";
}
“0 2 4” is printed.
Can you please explain the difference ?
Update:
The problem is not with i being global. This displays the same behavior:
flist = []
def outer():
for i in xrange(3):
def inner(x): return x * i
flist.append(inner)
outer()
#~ print i # commented because it causes an error
for f in flist:
print f(2)
As the commented line shows, i is unknown at that point. Still, it prints “4 4 4”.
Python is actually behaving as defined. Three separate functions are created, but they each have the closure of the environment they’re defined in – in this case, the global environment (or the outer function’s environment if the loop is placed inside another function). This is exactly the problem, though – in this environment, i is mutated, and the closures all refer to the same i.
Here is the best solution I can come up with – create a function creater and invoke that instead. This will force different environments for each of the functions created, with a different i in each one.
flist = []
for i in xrange(3):
def funcC(j):
def func(x): return x * j
return func
flist.append(funcC(i))
for f in flist:
print f(2)
This is what happens when you mix side effects and functional programming.
flist =[]for i in xrange(3):def func(x, i=i):# the *value* of i is copied in func() environmentreturn x * i
flist.append(func)for f in flist:print f(2)
The functions defined in the loop keep accessing the same variable i while its value changes. At the end of the loop, all the functions point to the same variable, which is holding the last value in the loop: the effect is what reported in the example.
In order to evaluate i and use its value, a common pattern is to set it as a parameter default: parameter defaults are evaluated when the def statement is executed, and thus the value of the loop variable is frozen.
The following works as expected:
flist = []
for i in xrange(3):
def func(x, i=i): # the *value* of i is copied in func() environment
return x * i
flist.append(func)
for f in flist:
print f(2)
回答 2
使用functools库的方法如下(提出问题时我不确定该库是否可用)。
from functools import partial
flist =[]def func(i, x):return x * ifor i in xrange(3):
flist.append(partial(func, i))for f in flist:print f(2)
Here’s how you do it using the functools library (which I’m not sure was available at the time the question was posed).
from functools import partial
flist = []
def func(i, x): return x * i
for i in xrange(3):
flist.append(partial(func, i))
for f in flist:
print f(2)
Outputs 0 2 4, as expected.
回答 3
看这个:
for f in flist:print f.func_closure(<cell at 0x00C980B0: int object at 0x009864B4>,)(<cell at 0x00C980B0: int object at 0x009864B4>,)(<cell at 0x00C980B0: int object at 0x009864B4>,)
这意味着它们都指向同一个i变量实例,循环结束后其值将为2。
可读的解决方案:
for i in xrange(3):def ffunc(i):def func(x):return x * ireturn func
flist.append(ffunc(i))
for f in flist:
print f.func_closure
(<cell at 0x00C980B0: int object at 0x009864B4>,)
(<cell at 0x00C980B0: int object at 0x009864B4>,)
(<cell at 0x00C980B0: int object at 0x009864B4>,)
It means they all point to the same i variable instance, which will have a value of 2 once the loop is over.
A readable solution:
for i in xrange(3):
def ffunc(i):
def func(x): return x * i
return func
flist.append(ffunc(i))
flist =[]def loop_body(i):# extract body of the for loop to functiondef func(x):return x*i
flist.append(func)
map(loop_body, xrange(3))# for i in xrange(3): body
What is happening is that the variable i is captured, and the functions are returning the value it is bound to at the time it is called. In functional languages this kind of situation never arises, as i wouldn’t be rebound. However with python, and also as you’ve seen with lisp, this is no longer true.
The difference with your scheme example is to do with the semantics of the do loop. Scheme is effectively creating a new i variable each time through the loop, rather than reusing an existing i binding as with the other languages. If you use a different variable created external to the loop and mutate it, you’ll see the same behaviour in scheme. Try replacing your loop with:
(let ((ii 1)) (
(do ((i 1 (+ 1 i)))
((>= i 4))
(set! flist
(cons (lambda (x) (* ii x)) flist))
(set! ii i))
))
Take a look here for some further discussion of this.
[Edit] Possibly a better way to describe it is to think of the do loop as a macro which performs the following steps:
Define a lambda taking a single parameter (i), with a body defined by the body of the loop,
An immediate call of that lambda with appropriate values of i as its parameter.
ie. the equivalent to the below python:
flist = []
def loop_body(i): # extract body of the for loop to function
def func(x): return x*i
flist.append(func)
map(loop_body, xrange(3)) # for i in xrange(3): body
The i is no longer the one from the parent scope but a brand new variable in its own scope (ie. the parameter to the lambda) and so you get the behaviour you observe. Python doesn’t have this implicit new scope, so the body of the for loop just shares the i variable.
I’m still not entirely convinced why in some languages this works one way, and in some another way. In Common Lisp it’s like Python:
(defvar *flist* '())
(dotimes (i 3 t)
(setf *flist*
(cons (lambda (x) (* x i)) *flist*)))
(dolist (f *flist*)
(format t "~a~%" (funcall f 2)))
Prints “6 6 6″ (note that here the list is from 1 to 3, and built in reverse”).
While in Scheme it works like in Perl:
(define flist '())
(do ((i 1 (+ 1 i)))
((>= i 4))
(set! flist
(cons (lambda (x) (* i x)) flist)))
(map
(lambda (f)
(printf "~a~%" (f 2)))
flist)
Prints “6 4 2”
And as I’ve mentioned already, Javascript is in the Python/CL camp. It appears there is an implementation decision here, which different languages approach in distinct ways. I would love to understand what is the decision, exactly.
The problem is that all of the local functions bind to the same environment and thus to the same i variable. The solution (workaround) is to create separate environments (stack frames) for each function (or lambda):
t = [ (lambda x: lambda y : x*y)(x) for x in range(5)]
>>> t[1](2)
2
>>> t[2](2)
4
回答 7
该变量i是全局变量,每次f调用该函数时其值为2 。
我倾向于实现以下行为:
>>>class f:...def __init__(self, multiplier): self.multiplier = multiplier...def __call__(self, multiplicand):return self.multiplier*multiplicand...>>> flist =[f(i)for i in range(3)]>>>[g(2)for g in flist][0,2,4]
The variable i is a global, whose value is 2 at each time the function f is called.
I would be inclined to implement the behavior you’re after as follows:
>>> class f:
... def __init__(self, multiplier): self.multiplier = multiplier
... def __call__(self, multiplicand): return self.multiplier*multiplicand
...
>>> flist = [f(i) for i in range(3)]
>>> [g(2) for g in flist]
[0, 2, 4]
Response to your update: It’s not the globalness of iper se which is causing this behavior, it’s the fact that it’s a variable from an enclosing scope which has a fixed value over the times when f is called. In your second example, the value of i is taken from the scope of the kkk function, and nothing is changing that when you call the functions on flist.
The reasoning behind the behavior has already been explained, and multiple solutions have been posted, but I think this is the most pythonic (remember, everything in Python is an object!):
flist = []
for i in xrange(3):
def func(x): return x * func.i
func.i=i
flist.append(func)
for f in flist:
print f(2)
Claudiu’s answer is pretty good, using a function generator, but piro’s answer is a hack, to be honest, as it’s making i into a “hidden” argument with a default value (it’ll work fine, but it’s not “pythonic”).
Recently I started playing around with Python and I came around something peculiar in the way closures work. Consider the following code:
adders=[None, None, None, None]
for i in [0,1,2,3]:
adders[i]=lambda a: i+a
print adders[1](3)
It builds a simple array of functions that take a single input and return that input added by a number. The functions are constructed in for loop where the iterator i runs from 0 to 3. For each of these numbers a lambda function is created which captures i and adds it to the function’s input. The last line calls the second lambda function with 3 as a parameter. To my surprise the output was 6.
I expected a 4. My reasoning was: in Python everything is an object and thus every variable is essential a pointer to it. When creating the lambda closures for i, I expected it to store a pointer to the integer object currently pointed to by i. That means that when i assigned a new integer object it shouldn’t effect the previously created closures. Sadly, inspecting the adders array within a debugger shows that it does. All lambda functions refer to the last value of i, 3, which results in adders[1](3) returning 6.
Which make me wonder about the following:
What do the closures capture exactly?
What is the most elegant way to convince the lambda functions to capture the current value of i in a way that will not be affected when i changes its value?
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:
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.
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 + x
adders = [createAdder(i) for i in range(4)]
回答 1
您可以使用具有默认值的参数来强制捕获变量:
>>>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
from functools import partial
from 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)
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 partial
from 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)
回答 3
考虑以下代码:
x ="foo"def print_x():print x
x ="bar"
print_x()# Outputs "bar"
x = "foo"
def print_x():
print x
x = "bar"
print_x() # Outputs "bar"
I think most people won’t find this confusing at all. It is the expected behaviour.
So, why do people think it would be different when it is done in a loop? I know I did that mistake myself, but I don’t know why. It is the loop? Or perhaps the lambda?
After all, the loop is just a shorter version of:
adders= [0,1,2,3]
i = 0
adders[i] = lambda a: i+a
i = 1
adders[i] = lambda a: i+a
i = 2
adders[i] = lambda a: i+a
i = 3
adders[i] = lambda a: i+a
In answer to your second question, the most elegant way to do this would be to use a function that takes two parameters instead of an array:
add = lambda a, b: a + b
add(1, 3)
However, using lambda here is a bit silly. Python gives us the operator module, which provides a functional interface to the basic operators. The lambda above has unnecessary overhead just to call the addition operator:
from operator import add
add(1, 3)
I understand that you’re playing around, trying to explore the language, but I can’t imagine a situation I would use an array of functions where Python’s scoping weirdness would get in the way.
If you wanted, you could write a small class that uses your array-indexing syntax:
class Adders(object):
def __getitem__(self, item):
return lambda a: a + item
adders = Adders()
adders[1](3)
回答 5
这是一个新的示例,突出显示了闭包的数据结构和内容,以帮助阐明何时“保存”了封闭的上下文。
def make_funcs():
i =42
my_str ="hi"
f_one =lambda: i
i +=1
f_two =lambda: i+1
f_three =lambda: my_str
return f_one, f_two, f_three
f_1, f_2, f_3 = make_funcs()
什么是封闭?
>>>print f_1.func_closure, f_1.func_closure[0].cell_contents
(<cell at 0x106a99a28: int object at 0x7fbb20c11170>,)43
值得注意的是,my_str不在f1的闭包中。
f2的闭包是什么?
>>>print f_2.func_closure, f_2.func_closure[0].cell_contents
(<cell at 0x106a99a28: int object at 0x7fbb20c11170>,)43
>>> print f_1.func_closure, f_1.func_closure[0].cell_contents
(<cell at 0x106a99a28: int object at 0x7fbb20c11170>,) 43
Notably, my_str is not in f1’s closure.
What’s in f2’s closure?
>>> print f_2.func_closure, f_2.func_closure[0].cell_contents
(<cell at 0x106a99a28: int object at 0x7fbb20c11170>,) 43
Notice (from the memory addresses) that both closures contain the same objects. So, you can start to think of the lambda function as having a reference to the scope. However, my_str is not in the closure for f_1 or f_2, and i is not in the closure for f_3 (not shown), which suggests the closure objects themselves are distinct objects.
Are the closure objects themselves the same object?
>>> print f_1.func_closure is f_2.func_closure
False
I have seen and used nested functions in Python, and they match the definition of a closure. So why are they called nested functions instead of closures?
Are nested functions not closures because they are not used by the external world?
UPDATE: I was reading about closures and it got me thinking about this concept with respect to Python. I searched and found the article mentioned by someone in a comment below, but I couldn’t completely understand the explanation in that article, so that is why I am asking this question.
When make_printer is called, a new frame is put on the stack with the compiled code for the printer function as a constant and the value of msg as a local. It then creates and returns the function. Because the function printer references the msg variable, it is kept alive after the make_printer function has returned.
So, if your nested functions don’t
access variables that are local to enclosing scopes,
do so when they are executed outside of that scope,
then they are not closures.
Here’s an example of a nested function which is not a closure.
Here, we are binding the value to the default value of a parameter. This occurs when the function printer is created and so no reference to the value of msg external to printer needs to be maintained after make_printer returns. msg is just a normal local variable of the function printer in this context.
>>> inn.func_closure
(<cell at 0x10c9807c0: str object at 0x10c9b0990>,<cell at 0x10c980f68: str object at 0x10c9eaf30>,<cell at 0x10c989130: str object at 0x10c831b98>)>>>for i in inn.func_closure:...print i.cell_contents
...
free
am
I
>>>
在这里,当我们调用时inn,它将引用所有save free变量,因此我们得到I am free variable
However, someone might be interested in how the variables are stored under the hood.
Before coming to the snippet:
Closures are functions that inherit variables from their enclosing environment. When you pass a function callback as an argument to another function that will do I/O, this callback function will be invoked later, and this function will — almost magically — remember the context in which it was declared, along with all the variables available in that context.
If a function does not use free variables it doesn’t form a closure.
If there is another inner level which uses free variables — all previous levels save the lexical environment ( example at the end )
function attributes func_closure in python < 3.X or __closure__ in python > 3.X save the free variables.
Every function in python has this closure attributes, but it doesn’t save any content if there is no free variables.
example: of closure attributes but no content inside as there is no free variable.
And all Python functions have a closure attribute so let’s examine the enclosing variables associated with a closure function.
Here is the attribute func_closure for the function printer
>>> 'func_closure' in dir(printer)
True
>>> printer.func_closure
(<cell at 0x108154c90: str object at 0x108151de0>,)
>>>
The closure attribute returns a tuple of cell objects which contain details of the variables defined in the enclosing scope.
The first element in the func_closure which could be None or a tuple of cells that contain bindings for the function’s free variables and it is read-only.
In the above snippet, I din’t print msg inside the printer function, so it doesn’t create any free variable. As there is no free variable, there will be no content inside the closure. Thats exactly what we see above.
Now I will explain another different snippet to clear out everything Free Variable with Closure:
>>> def outer(x):
... def intermediate(y):
... free = 'free'
... def inner(z):
... return '%s %s %s %s' % (x, y, free, z)
... return inner
... return intermediate
...
>>> outer('I')('am')('variable')
'I am free variable'
>>>
>>> inter = outer('I')
>>> inter.func_closure
(<cell at 0x10c989130: str object at 0x10c831b98>,)
>>> inter.func_closure[0].cell_contents
'I'
>>> inn = inter('am')
So, we see that a func_closure property is a tuple of closure cells, we can refer them and their contents explicitly — a cell has property “cell_contents”
>>> inn.func_closure
(<cell at 0x10c9807c0: str object at 0x10c9b0990>,
<cell at 0x10c980f68: str object at 0x10c9eaf30>,
<cell at 0x10c989130: str object at 0x10c831b98>)
>>> for i in inn.func_closure:
... print i.cell_contents
...
free
am
I
>>>
Here when we called inn, it will refer all the save free variables so we get I am free variable
function initCounter(){
var x =0;
function counter (){
x +=1;
console.log(x);};return counter;}
count = initCounter();
count();//Prints1
count();//Prints2
count();//Prints3
Python has a weak support for closure. To see what I mean take the following example of a counter using closure with JavaScript:
function initCounter(){
var x = 0;
function counter () {
x += 1;
console.log(x);
};
return counter;
}
count = initCounter();
count(); //Prints 1
count(); //Prints 2
count(); //Prints 3
Closure is quite elegant since it gives functions written like this the ability to have “internal memory”. As of Python 2.7 this is not possible. If you try
def initCounter():
x = 0;
def counter ():
x += 1 ##Error, x not defined
print x
return counter
count = initCounter();
count(); ##Error
count();
count();
You’ll get an error saying that x is not defined. But how can that be if it has been shown by others that you can print it? This is because of how Python it manages the functions variable scope. While the inner function can read the outer function’s variables, it cannot write them.
This is a shame really. But with just read-only closure you can at least implement the function decorator pattern for which Python offers syntactic sugar.
Update
As its been pointed out, there are ways to deal with python’s scope limitations and I’ll expose some.
1. Use the global keyword (in general not recommended).
2. In Python 3.x, use the nonlocal keyword (suggested by @unutbu and @leewz)
3. Define a simple modifiable class Object
class Object(object):
pass
and create an Object scope within initCounter to store the variables
Since scope is really just a reference, actions taken with its fields do not really modify scope itself, so no error arises.
4. An alternative way, as @unutbu pointed out, would be to define each variable as an array (x = [0]) and modify it’s first element (x[0] += 1). Again no error arises because x itself is not modified.
5. As suggested by @raxacoricofallapatorius, you could make x a property of counter
I had a situation where I needed a separate but persistent name space.
I used classes. I don’t otherwise.
Segregated but persistent names are closures.
>>> class f2:
... def __init__(self):
... self.a = 0
... def __call__(self, arg):
... self.a += arg
... return(self.a)
...
>>> f=f2()
>>> f(2)
2
>>> f(2)
4
>>> f(4)
8
>>> f(8)
16
# **OR**
>>> f=f2() # **re-initialize**
>>> f(f(f(f(2)))) # **nested**
16
# handy in list comprehensions to accumulate values
>>> [f(i) for f in [f2()] for i in [2,2,4,8]][-1]
16
回答 5
def nested1(num1):print"nested1 has",num1
def nested2(num2):print"nested2 has",num2,"and it can reach to",num1
return num1+num2 #num1 referenced for reading herereturn nested2
给出:
In[17]: my_func=nested1(8)
nested1 has 8In[21]: my_func(5)
nested2 has 5and it can reach to 8Out[21]:13
I’d like to offer another simple comparison between python and JS example, if this helps make things clearer.
JS:
function make () {
var cl = 1;
function gett () {
console.log(cl);
}
function sett (val) {
cl = val;
}
return [gett, sett]
}
and executing:
a = make(); g = a[0]; s = a[1];
s(2); g(); // 2
s(3); g(); // 3
Python:
def make ():
cl = 1
def gett ():
print(cl);
def sett (val):
cl = val
return gett, sett
and executing:
g, s = make()
g() #1
s(2); g() #1
s(3); g() #1
Reason: As many others said above, in python, if there is an assignment in the inner scope to a variable with the same name, a new reference in the inner scope is created. Not so with JS, unless you explicitly declare one with the var keyword.
A google search for “python nonlocal” turned up the Proposal, PEP 3104, which fully describes the syntax and reasoning behind the statement. in short, it works in exactly the same way as the global statement, except that it is used to refer to variables that are neither global nor local to the function.
Here’s a brief example of what you can do with this. The counter generator can be rewritten to use this so that it looks more like the idioms of languages with closures.
But while this is perfectly idiomatic python, it seems that the first version would be a bit more obvious for beginners. Properly using generators, by calling the returned function, is a common point of confusion. The first version explicitly returns a function.
It takes the one “closest” to the point of reference in the source code.
This is called “Lexical Scoping” and is standard for >40 years now.
Python’s class members are really in a dictionary called __dict__ and will never be reached by lexical scoping.
If you don’t specify nonlocal but do x = 7, it will create a new local variable “x”.
If you do specify nonlocal, it will find the “closest” “x” and assign to that.
If you specify nonlocal and there is no “x”, it will give you an error message.
The keyword global has always seemed strange to me since it will happily ignore all the other “x” except for the outermost one. Weird.
The nonlocal statement causes the listed identifiers to refer to
previously bound variables in the nearest enclosing scope. This is
important because the default behavior for binding is to search the
local namespace first. The statement allows encapsulated code to
rebind variables outside of the local scope besides the global
(module) scope.
Names listed in a nonlocal statement, unlike to those listed in a
global statement, must refer to pre-existing bindings in an
enclosing scope (the scope in which a new binding should be created
cannot be determined unambiguously).
Names listed in a nonlocal statement must not collide with pre-
existing bindings in the local scope.
See also:
PEP 3104 – Access to Names in Outer Scopes
The specification for the nonlocal statement.
def outer():def inner():def innermost():nonlocal x
x =3
x =2
innermost()if x ==3:print('Inner x has been modified')
x =1
inner()if x ==3:print('Outer x has been modified')
x =0
outer()if x ==3:print('Global x has been modified')# Inner x has been modified
“最近”变量可以相隔几个级别:
def outer():def inner():def innermost():nonlocal x
x =3
innermost()
x =1
inner()if x ==3:print('Outer x has been modified')
x =0
outer()if x ==3:print('Global x has been modified')# Outer x has been modified
但是它不能是全局变量:
def outer():def inner():def innermost():nonlocal x
x =3
innermost()
inner()
x =0
outer()if x ==3:print('Global x has been modified')# SyntaxError: no binding for nonlocal 'x' found
The nonlocal statement causes the listed identifiers to refer to previously bound variables in the nearest enclosing scope excluding globals.
As said in the reference, in case of several nested functions only variable in the nearest enclosing function is modified:
def outer():
def inner():
def innermost():
nonlocal x
x = 3
x = 2
innermost()
if x == 3: print('Inner x has been modified')
x = 1
inner()
if x == 3: print('Outer x has been modified')
x = 0
outer()
if x == 3: print('Global x has been modified')
# Inner x has been modified
The “nearest” variable can be several levels away:
def outer():
def inner():
def innermost():
nonlocal x
x = 3
innermost()
x = 1
inner()
if x == 3: print('Outer x has been modified')
x = 0
outer()
if x == 3: print('Global x has been modified')
# Outer x has been modified
But it cannot be a global variable:
def outer():
def inner():
def innermost():
nonlocal x
x = 3
innermost()
inner()
x = 0
outer()
if x == 3: print('Global x has been modified')
# SyntaxError: no binding for nonlocal 'x' found
回答 6
a =0#1. global variable with respect to every function in programdef f():
a =0#2. nonlocal with respect to function gdef g():nonlocal a
a=a+1print("The value of 'a' using nonlocal is ", a)def h():global a #3. using global variable
a=a+5print("The value of a using global is ", a)def i():
a =0#4. variable separated from all othersprint("The value of 'a' inside a function is ", a)
g()
h()
i()print("The value of 'a' global before any function", a)
f()print("The value of 'a' global after using function f ", a)
a = 0 #1. global variable with respect to every function in program
def f():
a = 0 #2. nonlocal with respect to function g
def g():
nonlocal a
a=a+1
print("The value of 'a' using nonlocal is ", a)
def h():
global a #3. using global variable
a=a+5
print("The value of a using global is ", a)
def i():
a = 0 #4. variable separated from all others
print("The value of 'a' inside a function is ", a)
g()
h()
i()
print("The value of 'a' global before any function", a)
f()
print("The value of 'a' global after using function f ", a)
My personal understanding of the “nonlocal” statement (and do excuse me as I am new to Python and Programming in general) is that the “nonlocal” is a way to use the Global functionality within iterated functions rather than the body of the code itself. A Global statement between functions if you will.
a =10defOuter(msg):
a =20
b =30defInner():
c =50
d =60print("MU LCL =",locals())nonlocal a
a =100
ans = a+c
print("Hello from Inner",ans)print("value of a Inner : ",a)Inner()print("value of a Outer : ",a)
res =Outer("Hello World")print(res)print("value of a Global : ",a)
with ‘nonlocal’ inner functions(ie;nested inner functions) can get read & ‘write‘ permission for that specific variable of the outer parent function. And nonlocal can be used only inside inner functions
eg:
a = 10
def Outer(msg):
a = 20
b = 30
def Inner():
c = 50
d = 60
print("MU LCL =",locals())
nonlocal a
a = 100
ans = a+c
print("Hello from Inner",ans)
print("value of a Inner : ",a)
Inner()
print("value of a Outer : ",a)
res = Outer("Hello World")
print(res)
print("value of a Global : ",a)
I’m trying to figure out Python lambdas. Is lambda one of those “interesting” language items that in real life should be forgotten?
I’m sure there are some edge cases where it might be needed, but given the obscurity of it, the potential of it being redefined in future releases (my assumption based on the various definitions of it) and the reduced coding clarity – should it be avoided?
This reminds me of overflowing (buffer overflow) of C types – pointing to the top variable and overloading to set the other field values. It feels like sort of a techie showmanship but maintenance coder nightmare.
Those things are actually quite useful. Python supports a style of programming called functional programming where you can pass functions to other functions to do stuff. Example:
Of course, in this particular case, you could do the same thing as a list comprehension:
mult3 = [x for x in [1, 2, 3, 4, 5, 6, 7, 8, 9] if x % 3 == 0]
(or even as range(3,10,3)), but there are many other, more sophisticated use cases where you can’t use a list comprehension and a lambda function may be the shortest way to write something out.
Returning a function from another function
>>> def transform(n):
... return lambda x: x + n
...
>>> f = transform(3)
>>> f(4)
7
This is often used to create function wrappers, such as Python’s decorators.
Combining elements of an iterable sequence with reduce()
I use lambda functions on a regular basis. It took me a while to get used to them, but eventually I came to understand that they’re a very valuable part of the language.
lambda is just a fancy way of saying function. Other than its name, there is nothing obscure, intimidating or cryptic about it. When you read the following line, replace lambda by function in your mind:
>>> f = lambda x: x + 1
>>> f(3)
4
It just defines a function of x. Some other languages, like R, say it explicitly:
> f = function(x) { x + 1 }
> f(3)
4
You see? It’s one of the most natural things to do in programming.
Closures: Very useful. Learn them, use them, love them.
Python’s lambda keyword: unnecessary, occasionally useful. If you find yourself doing anything remotely complex with it, put it away and define a real function.
A lambda is part of a very important abstraction mechanism which deals with higher order functions. To get proper understanding of its value, please watch high quality lessons from Abelson and Sussman, and read the book SICP
These are relevant issues in modern software business, and becoming ever more popular.
lambdas are extremely useful in GUI programming. For example, lets say you’re creating a group of buttons and you want to use a single paramaterized callback rather than a unique callback per button. Lambda lets you accomplish that with ease:
for value in ["one","two","three"]:
b = tk.Button(label=value, command=lambda arg=value: my_callback(arg))
b.pack()
(Note: although this question is specifically asking about lambda, you can also use functools.partial to get the same type of result)
The alternative is to create a separate callback for each button which can lead to duplicated code.
Curiously, the map, filter, and reduce functions that originally motivated the introduction of lambda and other functional features have to a large extent been superseded by list comprehensions and generator expressions. In fact, the reduce function was removed from list of builtin functions in Python 3.0. (However, it’s not necessary to send in complaints about the removal of lambda, map or filter: they are staying. :-)
My own two cents: Rarely is lambda worth it as far as clarity goes. Generally there is a more clear solution that doesn’t include lambda.
In Python, lambda is just a way of defining functions inline,
a = lambda x: x + 1
print a(1)
and..
def a(x): return x + 1
print a(1)
..are the exact same.
There is nothing you can do with lambda which you cannot do with a regular function—in Python functions are an object just like anything else, and lambdas simply define a function:
>>> a = lambda x: x + 1
>>> type(a)
<type 'function'>
I honestly think the lambda keyword is redundant in Python—I have never had the need to use them (or seen one used where a regular function, a list-comprehension or one of the many builtin functions could have been better used instead)
To see how lambda is broken, try generating a list of functions fs=[f0,...,f9] where fi(n)=i+n. First attempt:
>>> fs = [(lambda n: i + n) for i in range(10)]
>>> fs[3](4)
13
I would argue, even if that did work, it’s horribly and “unpythonic”, the same functionality could be written in countless other ways, for example:
>>> n = 4
>>> [i + n for i in range(10)]
[4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
Yes, it’s not the same, but I have never seen a cause where generating a group of lambda functions in a list has been required. It might make sense in other languages, but Python is not Haskell (or Lisp, or …)
Please note that we can use lambda and still achieve the desired
results in this way :
>>> fs = [(lambda n,i=i: i + n) for i in range(10)]
>>> fs[3](4)
7
Edit:
There are a few cases where lambda is useful, for example it’s often convenient when connecting up signals in PyQt applications, like this:
w = PyQt4.QtGui.QLineEdit()
w.textChanged.connect(lambda event: dothing())
Just doing w.textChanged.connect(dothing) would call the dothing method with an extra event argument and cause an error. Using the lambda means we can tidily drop the argument without having to define a wrapping function.
plural_rules =[lambda n:'all',lambda n:'singular'if n ==1else'plural',lambda n:'singular'if0<= n <=1else'plural',...]# Call plural rule #1 with argument 4 to find out which sentence form to use.
plural_rule[1](4)# returns 'plural'
plural_rules = [
lambda n: 'all',
lambda n: 'singular' if n == 1 else 'plural',
lambda n: 'singular' if 0 <= n <= 1 else 'plural',
...
]
# Call plural rule #1 with argument 4 to find out which sentence form to use.
plural_rule[1](4) # returns 'plural'
If you’d have to define a function for all of those you’d go mad by the end of it.
Also, it wouldn’t be nice with function names like plural_rule_1, plural_rule_2, etc. And you’d need to eval() it when you’re depending on a variable function id.
Pretty much anything you can do with lambda you can do better with either named functions or list and generator expressions.
Consequently, for the most part you should just one of those in basically any situation (except maybe for scratch code written in the interactive interpreter).
I’ve been using Python for a few years and I’ve never run in to a case where I’ve needed lambda. Really, as the tutorial states, it’s just for syntactic sugar.
I can’t speak to python’s particular implementation of lambda, but in general lambda functions are really handy. They’re a core technique (maybe even THE technique) of functional programming, and they’re also very useuful in object-oriented programs. For certain types of problems, they’re the best solution, so certainly shouldn’t be forgotten!
I suggest you read up on closures and the map function (that links to python docs, but it exists in nearly every language that supports functional constructs) to see why it’s useful.
回答 11
Lambda函数是创建函数的非官僚方式。
而已。例如,让我们假设您具有主要功能并且需要对值进行平方。让我们看看传统的方法和lambda方法:
传统方式:
def main():......
y = square(some_number)...return something
def square(x):return x**2
Lambda方法:
def main():...
square =lambda x: x**2
y = square(some_number)return something
Lambda function it’s a non-bureaucratic way to create a function.
That’s it. For example, let’s supose you have your main function and need to square values. Let’s see the traditional way and the lambda way to do this:
Lambda functions go very well with lists, like lists comprehensions or map. In fact, list comprehension it’s a “pythonic” way to express yourself using lambda. Ex:
>>>a = [1,2,3,4]
>>>[x**2 for x in a]
[1,4,9,16]
Let’s see what each elements of the syntax means:
[] : “Give me a list”
x**2 : “using this new-born function”
for x in a: “into each element in a”
That’s convenient uh? Creating functions like this. Let’s rewrite it using lambda:
>>> square = lambda x: x**2
>>> [square(s) for x in a]
[1,4,9,16]
Now let’s use map, which is the same thing, but more language-neutral. Maps takes 2 arguments:
(i) one function
(ii) an iterable
And gives you a list where each element it’s the function applied to each element of the iterable.
So, using map we would have:
>>> a = [1,2,3,4]
>>> squared_list = map(lambda x: x**2, a)
If you master lambdas and mapping, you will have a great power to manipulate data and in a concise way. Lambda functions are neither obscure nor take away code clarity. Don’t confuse something hard with something new. Once you start using them, you will find it very clear.
One of the nice things about lambda that’s in my opinion understated is that it’s way of deferring an evaluation for simple forms till the value is needed. Let me explain.
Many library routines are implemented so that they allow certain parameters to be callables (of whom lambda is one). The idea is that the actual value will be computed only at the time when it’s going to be used (rather that when it’s called). An (contrived) example might help to illustrate the point. Suppose you have a routine which which was going to do log a given timestamp. You want the routine to use the current time minus 30 minutes. You’d call it like so
Now suppose the actual function is going to be called only when a certain event occurs and you want the timestamp to be computed only at that time. You can do this like so
As stated above, the lambda operator in Python defines an anonymous function, and in Python functions are closures. It is important not to confuse the concept of closures with the operator lambda, which is merely syntactic methadone for them.
When I started in Python a few years ago, I used lambdas a lot, thinking they were cool, along with list comprehensions. However, I wrote and have to maintain a big website written in Python, with on the order of several thousand function points. I’ve learnt from experience that lambdas might be OK to prototype things with, but offer nothing over inline functions (named closures) except for saving a few key-stokes, or sometimes not.
Basically this boils down to several points:
it is easier to read software that is explicitly written using meaningful names. Anonymous closures by definition cannot have a meaningful name, as they have no name. This brevity seems, for some reason, to also infect lambda parameters, hence we often see examples like lambda x: x+1
it is easier to reuse named closures, as they can be referred to by name more than once, when there is a name to refer to them by.
it is easier to debug code that is using named closures instead of lambdas, because the name will appear in tracebacks, and around the error.
That’s enough reason to round them up and convert them to named closures. However, I hold two other grudges against anonymous closures.
The first grudge is simply that they are just another unnecessary keyword cluttering up the language.
The second grudge is deeper and on the paradigm level, i.e. I do not like that they promote a functional-programming style, because that style is less flexible than the message passing, object oriented or procedural styles, because the lambda calculus is not Turing-complete (luckily in Python, we can still break out of that restriction even inside a lambda). The reasons I feel lambdas promote this style are:
There is an implicit return, i.e. they seem like they ‘should’ be functions.
They are an alternative state-hiding mechanism to another, more explicit, more readable, more reusable and more general mechanism: methods.
I try hard to write lambda-free Python, and remove lambdas on sight. I think Python would be a slightly better language without lambdas, but that’s just my opinion.
def main():# define widgets and other imp stuff
x, y =None,None
widget.bind("<Button-1>",lambda event:do-something-cool(x, y))defdo-something-cool(event, x, y):
x = event.x
y = event.y
#Do other cool stuff
Lambdas are actually very powerful constructs that stem from ideas in functional programming, and it is something that by no means will be easily revised, redefined or removed in the near future of Python. They help you write code that is more powerful as it allows you to pass functions as parameters, thus the idea of functions as first-class citizens.
Lambdas do tend to get confusing, but once a solid understanding is obtained, you can write clean elegant code like this:
squared = map(lambda x: x*x, [1, 2, 3, 4, 5])
The above line of code returns a list of the squares of the numbers in the list. Ofcourse, you could also do it like:
It is obvious the former code is shorter, and this is especially true if you intend to use the map function (or any similar function that takes a function as a parameter) in only one place. This also makes the code more intuitive and elegant.
Also, as @David Zaslavsky mentioned in his answer, list comprehensions are not always the way to go especially if your list has to get values from some obscure mathematical way.
From a more practical standpoint, one of the biggest advantages of lambdas for me recently has been in GUI and event-driven programming. If you take a look at callbacks in Tkinter, all they take as arguments are the event that triggered them. E.g.
def define_bindings(widget):
widget.bind("<Button-1>", do-something-cool)
def do-something-cool(event):
#Your code to execute on the event trigger
Now what if you had some arguments to pass? Something as simple as passing 2 arguments to store the coordinates of a mouse-click. You can easily do it like this:
def main():
# define widgets and other imp stuff
x, y = None, None
widget.bind("<Button-1>", lambda event: do-something-cool(x, y))
def do-something-cool(event, x, y):
x = event.x
y = event.y
#Do other cool stuff
Now you can argue that this can be done using global variables, but do you really want to bang your head worrying about memory management and leakage especially if the global variable will just be used in one particular place? That would be just poor programming style.
In short, lambdas are awesome and should never be underestimated. Python lambdas are not the same as LISP lambdas though (which are more powerful), but you can really do a lot of magical stuff with them.
Lambdas are deeply linked to functional programming style in general. The idea that you can solve problems by applying a function to some data, and merging the results, is what google uses to implement most of its algorithms.
Programs written in functional programming style, are easily parallelized and hence are becoming more and more important with modern multi-core machines.
So in short, NO you should not forget them.
First congrats that managed to figure out lambda. In my opinion this is really powerful construct to act with. The trend these days towards functional programming languages is surely an indicator that it neither should be avoided nor it will be redefined in the near future.
You just have to think a little bit different. I’m sure soon you will love it. But be careful if you deal only with python. Because the lambda is not a real closure, it is “broken” somehow: pythons lambda is broken
I’m just beginning Python and ran head first into Lambda- which took me a while to figure out.
Note that this isn’t a condemnation of anything. Everybody has a different set of things that don’t come easily.
Is lambda one of those ‘interesting’ language items that in real life should be forgotten?
No.
I’m sure there are some edge cases where it might be needed, but given the obscurity of it,
It’s not obscure. The past 2 teams I’ve worked on, everybody used this feature all the time.
the potential of it being redefined in future releases (my assumption based on the various definitions of it)
I’ve seen no serious proposals to redefine it in Python, beyond fixing the closure semantics a few years ago.
and the reduced coding clarity – should it be avoided?
It’s not less clear, if you’re using it right. On the contrary, having more language constructs available increases clarity.
This reminds me of overflowing (buffer overflow) of C types – pointing to the top variable and overloading to set the other field values…sort of a techie showmanship but maintenance coder nightmare..
Lambda is like buffer overflow? Wow. I can’t imagine how you’re using lambda if you think it’s a “maintenance nightmare”.
I started reading David Mertz’s book today ‘Text Processing in Python.’ While he has a fairly terse description of Lambda’s the examples in the first chapter combined with the explanation in Appendix A made them jump off the page for me (finally) and all of a sudden I understood their value. That is not to say his explanation will work for you and I am still at the discovery stage so I will not attempt to add to these responses other than the following:
I am new to Python
I am new to OOP
Lambdas were a struggle for me
Now that I read Mertz, I think I get them and I see them as very useful as I think they allow a cleaner approach to programming.
He reproduces the Zen of Python, one line of which is Simple is better than complex. As a non-OOP programmer reading code with lambdas (and until last week list comprehensions) I have thought-This is simple?. I finally realized today that actually these features make the code much more readable, and understandable than the alternative-which is invariably a loop of some sort. I also realized that like financial statements-Python was not designed for the novice user, rather it is designed for the user that wants to get educated. I can’t believe how powerful this language is. When it dawned on me (finally) the purpose and value of lambdas I wanted to rip up about 30 programs and start over putting in lambdas where appropriate.
A useful case for using lambdas is to improve the readability of long list comprehensions.
In this example loop_dic is short for clarity but imagine loop_dic being very long. If you would just use a plain value that includes i instead of the lambda version of that value you would get a NameError.
I can give you an example where I actually needed lambda serious. I’m making a graphical program, where the use right clicks on a file and assigns it one of three options. It turns out that in Tkinter (the GUI interfacing program I’m writing this in), when someone presses a button, it can’t be assigned to a command that takes in arguments. So if I chose one of the options and wanted the result of my choice to be:
print 'hi there'
Then no big deal. But what if I need my choice to have a particular detail. For example, if I choose choice A, it calls a function that takes in some argument that is dependent on the choice A, B or C, TKinter could not support this. Lamda was the only option to get around this actually…
I use lambda to create callbacks that include parameters. It’s cleaner writing a lambda in one line than to write a method to perform the same functionality.
Lambda is a procedure constructor. You can synthesize programs at run-time, although Python’s lambda is not very powerful. Note that few people understand that kind of programming.