为什么python嵌套函数不称为闭包?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4020419/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why aren't python nested functions called closures?
提问by Srikar Appalaraju
I have seen and used nested functions in Python, and they match the definition of a closure. So why are they called nested functionsinstead of closures?
我在 Python 中看到并使用过嵌套函数,它们与闭包的定义相匹配。那么为什么他们被称为nested functions而不是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.
更新:我正在阅读有关闭包的内容,这让我想到了与 Python 相关的这个概念。我搜索并找到了下面评论中有人提到的文章,但我无法完全理解那篇文章中的解释,所以这就是我问这个问题的原因。
采纳答案by aaronasterling
A closure occurs when a function has access to a local variable from an enclosing scope that has finished its execution.
当函数可以从已完成执行的封闭作用域访问局部变量时,就会发生闭包。
def make_printer(msg):
def printer():
print msg
return printer
printer = make_printer('Foo!')
printer()
When make_printeris called, a new frame is put on the stack with the compiled code for the printerfunction as a constant and the value of msgas a local. It then creates and returns the function. Because the function printerreferences the msgvariable, it is kept alive after the make_printerfunction has returned.
当make_printer被调用时,一个新的帧被放在堆栈上,printer函数的编译代码作为一个常量,值msg作为一个局部变量。然后它创建并返回函数。因为函数printer引用了该msg变量,所以在make_printer函数返回后它会保持活动状态。
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.
这是一个不是闭包的嵌套函数的例子。
def make_printer(msg):
def printer(msg=msg):
print msg
return printer
printer = make_printer("Foo!")
printer() #Output: Foo!
Here, we are binding the value to the default value of a parameter. This occurs when the function printeris created and so no reference to the value of msgexternal to printerneeds to be maintained after make_printerreturns. msgis just a normal local variable of the function printerin this context.
在这里,我们将值绑定到参数的默认值。这发生在printer创建函数时,因此返回 后不需要维护对msgexternal to值的引用。在这个上下文中只是函数的一个普通局部变量。printermake_printermsgprinter
回答by James Sapam
The question has already been answered byaaronasterling
aaronasterling已经回答了这个问题
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.
闭包是从其封闭环境继承变量的函数。当你将一个函数回调作为参数传递给另一个将执行 I/O 的函数时,这个回调函数将在稍后被调用,并且这个函数将——几乎神奇地——记住它被声明的上下文,以及所有可用的变量在这种情况下。
If a function does not use free variables it doesn't form a closure.
If there is another inner level which uses free variables -- allprevious levels save the lexical environment ( example at the end )
function attributes
func_closurein 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.
如果函数不使用自由变量,则不会形成闭包。
如果有另一个使用自由变量的内部级别 -所有以前的级别都保存词法环境(最后的示例)
功能属性
func_closure在蟒<3.X或__closure__在python> 3.X节省的自由变量。python中的每个函数都有这个闭包属性,但是如果没有自由变量,它不会保存任何内容。
example: of closure attributes but no content inside as there is no free variable.
示例:闭包属性但内部没有内容,因为没有自由变量。
>>> def foo():
... def fii():
... pass
... return fii
...
>>> f = foo()
>>> f.func_closure
>>> 'func_closure' in dir(f)
True
>>>
NB: FREE VARIABLEIS MUST TO CREATE A CLOSURE.
注意:创建闭包必须使用自由变量。
I will explain using the same snippet as above:
我将使用与上面相同的代码段进行解释:
>>> def make_printer(msg):
... def printer():
... print msg
... return printer
...
>>> printer = make_printer('Foo!')
>>> printer() #Output: Foo!
And all Python functions have a closure attribute so let's examine the enclosing variables associated with a closure function.
并且所有 Python 函数都有一个闭包属性,所以让我们检查与闭包函数关联的封闭变量。
Here is the attribute func_closurefor the function printer
这是func_closure函数的属性printer
>>> 'func_closure' in dir(printer)
True
>>> printer.func_closure
(<cell at 0x108154c90: str object at 0x108151de0>,)
>>>
The closureattribute returns a tuple of cell objects which contain details of the variables defined in the enclosing scope.
该closure属性返回一个单元格对象元组,其中包含在封闭范围内定义的变量的详细信息。
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.
func_closure 中的第一个元素可以是 None 或包含函数自由变量绑定的单元格元组,它是只读的。
>>> dir(printer.func_closure[0])
['__class__', '__cmp__', '__delattr__', '__doc__', '__format__', '__getattribute__',
'__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'cell_contents']
>>>
Here in the above output you can see cell_contents, let's see what it stores:
在上面的输出中你可以看到cell_contents,让我们看看它存储了什么:
>>> printer.func_closure[0].cell_contents
'Foo!'
>>> type(printer.func_closure[0].cell_contents)
<type 'str'>
>>>
So, when we called the function printer(), it accesses the value stored inside the cell_contents. This is how we got the output as 'Foo!'
因此,当我们调用函数时printer(),它访问存储在cell_contents. 这就是我们如何得到“Foo!”的输出
Again I will explain using the above snippet with some changes:
我将再次解释使用上面的代码片段并进行一些更改:
>>> def make_printer(msg):
... def printer():
... pass
... return printer
...
>>> printer = make_printer('Foo!')
>>> printer.func_closure
>>>
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.
在上面的代码片段中,我没有在打印机函数中打印 msg,所以它不会创建任何自由变量。由于没有自由变量,闭包内将没有内容。这正是我们在上面看到的。
Now I will explain another different snippet to clear out everything Free Variablewith Closure:
现在,我将解释另一个不同的片段,以清除一切Free Variable有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_closureproperty is a tuple of closure cells, we can refer them and their contents explicitly -- a cell has property "cell_contents"
所以,我们看到一个func_closure属性是一个闭包单元的元组,我们可以明确地引用它们和它们的内容——一个单元有属性“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
在这里,当我们调用时inn,它将引用所有可保存的变量,因此我们得到I am free variable
>>> inn('variable')
'I am free variable'
>>>
回答by Krcn U
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 here
return nested2
Gives:
给出:
In [17]: my_func=nested1(8)
nested1 has 8
In [21]: my_func(5)
nested2 has 5 and it can reach to 8
Out[21]: 13
This is an example of what a closure is and how it can be used.
这是一个闭包是什么以及如何使用它的例子。
回答by Cristian Garcia
Python has a weaksupport for closure. To see what I mean take the following example of a counter using closure with JavaScript:
Python对闭包的支持很弱。要了解我的意思,请看以下使用 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
闭包非常优雅,因为它使这样编写的函数具有“内部存储器”的能力。从 Python 2.7 开始,这是不可能的。如果你试试
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 readthe outer function's variables, it cannot writethem.
您会收到一条错误消息,指出 x 未定义。但是,如果其他人已经证明您可以打印它,那怎么可能呢?这是因为 Python 如何管理函数变量范围。虽然内部函数可以读取外部函数的变量,但不能写入它们。
This is a shame really. But with just read-only closure you can at least implement the function decorator patternfor which Python offers syntactic sugar.
这真的是一种耻辱。但是只要使用只读闭包,您至少可以实现Python 为其提供语法糖的函数装饰器模式。
Update
更新
As its been pointed out, there are ways to deal with python's scope limitations and I'll expose some.
正如它所指出的,有一些方法可以处理 python 的范围限制,我将公开一些。
1.Use the globalkeyword (in general not recommended).
1.使用global关键字(一般不推荐)。
2.In Python 3.x, use the nonlocalkeyword (suggested by @unutbu and @leewz)
2.在 Python 3.x 中,使用nonlocal关键字(@unutbu 和 @leewz 建议)
3.Define a simple modifiable class Object
3.定义一个简单的可修改类Object
class Object(object):
pass
and create an Object scopewithin initCounterto store the variables
并创建一个 Object scope内initCounter来存储变量
def initCounter ():
scope = Object()
scope.x = 0
def counter():
scope.x += 1
print scope.x
return counter
Since scopeis really just a reference, actions taken with its fields do not really modify scopeitself, so no error arises.
由于scope实际上只是一个参考,因此对其字段采取的操作不会真正修改scope自身,因此不会出现错误。
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 xitself is not modified.
4.正如@unutbu 指出的那样,另一种方法是将每个变量定义为一个数组 ( x = [0]) 并修改它的第一个元素 ( x[0] += 1)。同样没有错误出现,因为x它本身没有被修改。
5.As suggested by @raxacoricofallapatorius, you could make xa property of counter
5.正如@raxacoricofallapatorius 所建议的,您可以创建x一个属性counter
def initCounter ():
def counter():
counter.x += 1
print counter.x
counter.x = 0
return counter
回答by fp_mora
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
回答by Lee Benson
Python 2 didn't have closures - it had workarounds that resembledclosures.
Python 2 没有闭包——它有类似于闭包的变通方法。
There are plenty of examples in answers already given - copying in variables to the inner function, modifying an object on the inner function, etc.
已经给出的答案中有很多示例 - 将变量复制到内部函数,修改内部函数上的对象等。
In Python 3, support is more explicit - and succinct:
在 Python 3 中,支持更加明确 - 并且简洁:
def closure():
count = 0
def inner():
nonlocal count
count += 1
print(count)
return inner
Usage:
用法:
start = closure()
start() # prints 1
start() # prints 2
start() # prints 3
The nonlocalkeyword binds the inner function to the outer variable explicitly mentioned, in effect enclosing it. Hence more explicitly a 'closure'.
的nonlocal关键词结合的内函数来明确提到的外变量,实际上包围它。因此更明确地是“关闭”。
回答by forumulator
I'd like to offer another simple comparison between python and JS example, if this helps make things clearer.
如果这有助于使事情更清晰,我想提供 python 和 JS 示例之间的另一个简单比较。
JS:
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:
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 varkeyword.
原因:正如上面许多人所说,在python中,如果在内部作用域中对同名变量进行赋值,则会在内部作用域中创建一个新的引用。JS 不是这样,除非你明确地用var关键字声明一个。

