Python3之闭包

何为闭包
维基百科中关于闭包的概念:
在一些语言中,在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包。闭包可以用来在一个函数与一组“私有”变量之间创建关联关系。在给定函数被多次调用的过程中,这些私有变量能够保持其持久性。

 

闭包条件

根据这句话,其实我们自己就可以总结出在python语言中形成闭包的三个条件,缺一不可:
1)必须有一个内嵌函数(函数里定义的函数)——这对应函数之间的嵌套
2)内嵌函数必须引用一个定义在闭合范围内(外部函数里)的变量——内部函数引用外部变量
3)外部函数必须返回内嵌函数——必须返回那个内部函数

前两个条件我们比较好理解,那什么会有第三条规定呢?其实闭包一词指的就是上文中提到的那个“内部的函数”,我们下面就会发现,只有那个内部函数才有所谓的__closure__属性。

我们首先来创造一个闭包:

def funx():
    x=5
    def funy():
        nonlocal x
        x+=1
        return x
    return funy

我们根据上面的三准则创造了一个函数,其中的funy就是所谓的闭包,而funy内部所引用过的x就是所谓的闭包变量。

测试:

>>> a=funx()
>>> a()
6
>>> a()
7
>>> a()
8
>>> a()
9
>>> x
Traceback (most recent call last):
  File "<pyshell#19>", line 1, in <module>
    x
NameError: name 'x' is not defined
>>>

我们会发现,funx中的x变量原本仅仅是funx的一个局部变量。但是形成了闭包之后,它的行为就好像是一个全局变量一样。但是最后的错误说明x并不是一个全局变量。其实这就是闭包的一个十分浅显的作用,形成闭包之后,闭包变量能够随着闭包函数的调用而实时更新,就好像是一个全局变量那样。(注意我们上面的a=funx(),a实际上应该是funy,所以a称为闭包)


进一步探究
我们能否找出点证据证明我们对于闭包的猜想呢?很简单,我们可以尝试下面的操作:

>>> a.__closure__
(<cell at 0x0000002F346FB408: int object at 0x00000000667D02D0>,)
>>> type(a.__closure__)
<class 'tuple'>
>>> type(a.__closure__[0])
<class 'cell'>
>>> a.__closure__[0].cell_contents
9
>>> a()
10
>>> a.__closure__[0].cell_contents
10
>>> def test():pass

>>> test.__closure__==None
True
>>>

这样我们就明白了,形成闭包之后,闭包函数会获得一个非空的__closure__属性(对比我们最后的函数test,test是一个不具备闭包的函数,它的__closure__属性是None),这个属性是一个元组。元组里面的对象为cell对象,而访问cell对象的cell_contents属性则可以得到闭包变量的当前值(即上一次调用之后的值)。而随着闭包的继续调用,变量会再次更新。所以可见,一旦形成闭包之后,python确实会将__closure__和闭包函数绑定作为储存闭包变量的场所。

def outer():
    count = 0
    def inner():
        nonlocal count
        count +=1
        return count
    return inner


f=outer()
print(f())
print(f())

# 输出
1
2
>>>


#nonlocal count出错,count不能为全局变量
count = 0
def outer():
    def inner():
        nonlocal count
        count +=1
        return count
    return inner


f=outer()
print(f())
print(f())

猜你喜欢

转载自blog.csdn.net/llf_cloud/article/details/82426604