本文需要您有Python变量查找的知识,如果您不知道,可以参考上篇博文Python变量查找LEGB原则

构成闭包的条件

  • 外函数中定义了内函数
  • 内函数使用了外函数的变量
  • 外函数的返回值是内函数的引用

以下是一个简单的闭包的定义

def outer():
    b = 1
    def inner(): #外部函数内定义了内部函数
        print(b) #内部函数使用了外部函数的变量
    return inner #外部函数的返回值是内函数的引用

使用

a = outer()
a() #1

我们先是调用了外部函数outer()将其返回值赋值给了a变量,那么a变量实际上是指向的内部函数inner,当我们调用a时,相当于调用了inner,然后打印了外部变量b的值。
似乎没什么不妥
但是,我们知道,函数中的局部变量,在函数结束时会释放掉,但是上例中,执行a()的时候outer()已经退出了,那么对应的b也就释放了,但是inner还调用了b变量,这就是闭包

闭包变量是如何使用的?

实际上,解释器会将内函数中使用的外函数变量绑定给内函数,看代码:

def outer():
    a = 10
    def inner():
        print(a)
        print(locals()) #{'a': 10}
    return inner
outer()()

对变量的修改

这个也是分情况,可变及不可变:
可变变量

def outer():
    a = []
    def inner():
        print(a)
        a.append(1)
        print(locals())
    return inner
outer()()

没任何问题。

再看看不可变变量

def outer():
    a = 10
    def inner():
        print(a) #UnboundLocalError: local variable 'a' referenced before assignment
        a = 20 
        print(locals())
    return inner
outer()()

可见和和上篇博文中的情况一样,但是这次的解决方法不是global而是nonlocal声明。

def outer():
    a = 10
    def inner():
        nonlocal a
        print(a)
        a = 20
        print(locals())
    return inner
outer()()

那么闭包有什么作用的,答案是装饰器,我们下节详细讨论。

posted on 2018-04-08 21:03  岚漾忆雨  阅读(20)  评论(0)    收藏  举报