为什么不是称为闭包的python嵌套函数?
我已经看到并在Python中使用嵌套函数,它们匹配闭包的定义。 那么为什么他们调用nested functions
而不是closures
?
嵌套函数是不是因为它们不被外部世界使用而关闭?
更新:我正在阅读关于闭包的知识,这让我想起了关于Python的这个概念。 我在下面的评论中搜索并找到了某人提到的文章,但是我无法完全理解那篇文章中的解释,所以这就是我为什么要问这个问题的原因。
当函数可以从已经完成执行的封闭作用域访问局部变量时,会发生闭包。
def make_printer(msg):
def printer():
print msg
return printer
printer = make_printer('Foo!')
printer()
当make_printer
,会在堆栈中放置一个新框架,并将printer
函数的编译代码作为常量,将msg
的值作为本地值。 然后它创建并返回该函数。 由于函数printer
引用了msg
变量,因此在make_printer
函数返回后它会保持活动状态。
所以,如果你的嵌套函数不
那么他们不是关闭。
这是一个嵌套函数的例子,它不是闭包。
def make_printer(msg):
def printer(msg=msg):
print msg
return printer
printer = make_printer("Foo!")
printer() #Output: Foo!
在这里,我们将该值绑定到参数的默认值。 这发生在创建功能printer
时,因此在make_printer
返回后, make_printer
维护对printer
外部msg
值的引用。 在这种情况下, msg
只是功能printer
的常规局部变量。
这个问题已经由 aaronasterling 回答了
但是,有人可能对如何将变量存储在引擎盖下感兴趣。
在加入片段之前:
闭包是从其环境中继承变量的函数。 将函数回调作为参数传递给另一个将执行I / O的函数时,稍后会调用此回调函数,并且此函数会 - 几乎神奇地记住它声明的上下文以及所有可用变量在这方面。
如果一个函数不使用自由变量,它不会形成闭包。
如果有另一个使用自由变量的内部级别 - 所有以前的级别保存词汇环境(例如最后)
函数属性func_closure
在python <3.X或__closure__
在python> 3.X中保存自由变量。
python中的每个函数都有这个闭包属性,但是如果没有自由变量,它不会保存任何内容。
例如:关闭属性,但没有内容,因为没有自由变量。
>>> def foo():
... def fii():
... pass
... return fii
...
>>> f = foo()
>>> f.func_closure
>>> 'func_closure' in dir(f)
True
>>>
注意:自由变量必须创建关闭。
我将使用与上面相同的片段来解释:
>>> def make_printer(msg):
... def printer():
... print msg
... return printer
...
>>> printer = make_printer('Foo!')
>>> printer() #Output: Foo!
所有的Python函数都有一个闭包属性,所以让我们来看看与闭包函数相关的封闭变量。
这是功能printer
的属性func_closure
>>> 'func_closure' in dir(printer)
True
>>> printer.func_closure
(<cell at 0x108154c90: str object at 0x108151de0>,)
>>>
closure
属性返回一个元组对象,它包含在封闭范围中定义的变量的细节。
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']
>>>
在上面的输出中,您可以看到cell_contents
,让我们看看它存储的内容:
>>> printer.func_closure[0].cell_contents
'Foo!'
>>> type(printer.func_closure[0].cell_contents)
<type 'str'>
>>>
所以,当我们调用函数printer()
,它会访问存储在cell_contents
的值。 这就是我们如何得到输出为'Foo!'
再次,我会解释一下使用上面的代码片段:
>>> def make_printer(msg):
... def printer():
... pass
... return printer
...
>>> printer = make_printer('Foo!')
>>> printer.func_closure
>>>
在上面的代码片段中,我不打印打印机函数中的msg,所以它不会创建任何自由变量。 由于没有可用变量,因此闭包内不会有内容。 这正是我们上面看到的。
现在我将解释另一个不同的片段来清除Free Variable
Closure
所有Free Variable
:
>>> 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')
因此,我们看到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
>>>
在这里,当我们调用inn
,它会引用所有保存的自由变量,所以我们得到的I am free variable
>>> inn('variable')
'I am free variable'
>>>
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
关闭是非常优雅的,因为它赋予这样写的功能具有“内部存储器”的能力。 从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();
你会得到一个错误,说x没有被定义。 但是如果其他人已经证明你可以打印它,那怎么可能呢? 这是因为它如何管理函数变量作用域。 虽然内部函数可以读取外部函数的变量,但它不能写入它们。
这真的很遗憾。 但是只用read-only闭包,你至少可以实现Python为其提供语法糖的函数装饰器模式。
更新
正如它已经指出的,有办法来处理python的范围限制,我会公开一些。
1.使用global
关键字(通常不推荐)。
2.定义一个简单的可修改类Object
class Object(object):
pass
并在initCounter
创建一个Object scope
来存储变量
def initCounter ():
scope = Object()
scope.x = 0
def counter():
scope.x += 1
print scope.x
return counter
由于scope
实际上只是一个参考,因此使用其域的操作并不真正修改scope
本身,因此不会出现错误。
3.另一种方式,如@unutbu指出的那样,将每个变量定义为一个数组( x = [0]
)并修改它的第一个元素( x[0] += 1
)。 再次没有出现错误,因为x
本身没有被修改。
4.按照@raxacoricofallapatorius的建议,你可以使x
成为counter
一个属性
def initCounter ():
def counter():
counter.x += 1
print counter.x
counter.x = 0
return counter
链接地址: http://www.djcxy.com/p/9047.html