原文:http://www.programiz.com/python-programming/closure
一个函数定义在另一个函数内部叫做嵌套函数。嵌套的函数能够访问enclosing scope作用域的变量。在Python中,非局部(non-local)变量是只读的,如果要修改它们必须使用nonlocal关键字显示申明。
下面是一个嵌套函数访问非局部变量的例子:
def print_msg(msg):
'''This is the outer enclosing function'''
def printer():
'''This is the nested function'''
print(msg)
printer()
执行函数结果如下:
>>> print_msg("Hello")
Hello
我们发现嵌套的函数printer()能够访问非局部变量msg。如果我们将上面函数中最后一条语句printer()改成返回printer函数会怎样呢?
如下所示:
def print_msg(msg):
'''This is the outer enclosing function'''
def printer():
'''This is the nested function'''
print(msg)
return printer # 这条语句变了
我们尝试调用这个新的函数
>>> print_msg("Hello")
<function print_msg.<locals>.printer at 0x02AB4108>
>>> another = print_msg("Hello") # calling it like this
>>> another()
Hello
很奇怪是吧。传入参数"Hello", print_msg()函数被调用并且返回的函数绑定到了一个叫another的对象。调用another(), 输出结果跟先前的一致,虽然print_msg()函数已经执行过了。
这种将一些数据('Hello')附加到代码的技术在Python中叫做闭包。
This technique by which some data ("Hello") gets attached to the code is called closure in Python. - See more at: http://www.programiz.com/python-programming/closure#sthash.uvOo9v91.dpuf
This technique by which some data ("Hello") gets attached to the code is called closure in Python. - See more at: http://www.programiz.com/python-programming/closure#sthash.uvOo9v91.dpuf
This technique by which some data ("Hello") gets attached to the code is called closure in Python. - See more at: http://www.programiz.com/python-programming/closure#sthash.uvOo9v91.dpuf
This technique by which some data ("Hello") gets attached to the code is called closure in Python. - See more at: http://www.programiz.com/python-programming/closure#sthash.uvOo9v91.dpuf
This technique by which some data ("Hello") gets attached to the code is called closure in Python.
即使变量离开了作用域或者函数已经从命名空间中删除,enclosing 作用域的值仍然能被程序记住
>>> del print_msg
>>> foo() # This does work still
Hello
>>> print_msg('Hello')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'print_msg' is not defined
>>>
什么时候会产生闭包?
从上面的例子可以看出,当一个嵌套函数访问enclosing作用域的变量时就会产生闭包。
在Python中要创建闭包需满足下面的条件:
- 必须有一个嵌套函数(一个函数定义在另一个函数内部)
- 嵌套的(nested, the inside function)函数必须访问定义在嵌套(enclosing, the outer function)函数中的变量
- 嵌套函数必须返回嵌套的函数
什么时候使用闭包?
那么闭包适合用来干嘛呢?闭包能够避免使用全局变量,能够提供某种形式的数据隐藏。针对某些问题能够提供一个面向对象的解决方案。当一个类只需要实现少数几个方法的时候,闭包可以提供一种可选的和更加优雅的解决方案。当然,当类的属性和方法足够多的时候还是使用类吧。
下面是一个使用闭包代替类的例子:
def make_multiplier_of(n):
def multiplier(x):
return x * n
return multiplier
# Here is how can we use it
>>> times3 = make_multiplier_of(3)
>>> times5 = make_multiplier_of(5)
>>> times3(9)
27
>>> times5(3)
15
>>> times5(times3(2))
30
Python中的装饰器(decorator)也使用了闭包。
所有的函数对象都有__closure__属性,一个闭包函数的__closure__属性会返回一个cell对象的元组。
查看下上面例子中的闭包函数make_multiplier_of:
>>> make_multiplier_of.__closure__
>>> times3.__closure__
(<cell at 0x02ABB230: int object at 0x1D75C030>,)
>>>
cell对象具有cell_contents属性,该属性存储了the closed value.
>>> times3.__closure__[0].cell_contents
3
>>> times5.__closure__[0].cell_contents
5