Python 闭包

原文: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





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值