Python闭包

闭包函数的介绍

闭包函数:内部函数包含对外部作用域非全局作用域名字的引用,并且一般外部函数的返回值为内部函数,这个内部函数叫做闭包函数。

闭:内部函数

包:内部函数引用了外部函数作用域的名称

闭包函数示例:

def outter():
    x = 111
    def inner():
        print(x)
    return inner

res = outter() #res 就是内部函数 inner

下面这个就不是闭包函数:

x = 1
def outter():
    def inner():
        print(x)

    return inner

说明:因为x是全局作用域的变量,内部函数inner,包含的是全局作用域x的引用,根据闭包函数的定义,只有包含局部作用域名称的引用才是闭包函数。所以inner不是闭包函数。 

函数.__closure__的返回值是一个cell对象组成的元组对象的话,那么这个函数是闭包函数。

如果返回值为None,则不是闭包函数。

def outter():
    x = 1
    y = 2
    def inner():
        print(x)
        print(y)
    print('inner', inner.__closure__)
    return inner

res = outter()
print(res.__closure__[0].cell_contents)
print(res.__closure__[1].cell_contents)

>>>inner (<cell at 0x1047f9ac8: int object at 0x1045abc00>, <cell at 0x1047f9af8: int object at 0x1045abc20>)
>>>1  (x的值)
>>>2  (y的值)

说明:__closure__ 返回的长度等于局部作用域的名称的引用数量。可以看到元组中有两个cell,因为在闭包函数inner中,包含了两个局部作用域名称的引用。

Python循环中不包含域的概念:

func_list = []

for i in range(3):

    def fun(x):
        return x*i

    func_list.append(fun)

for func in func_list:
    print(func(3))

>>>6
>>>6
>>>6

当函数参数传入3时,如果想让结果为 0, 3 ,6 时,这时候就要用到闭包

func_list = []

for i in range(3):
    def outter(i):
        def fun(x):
            return x*i
        return fun

    func_list.append(outter(i))

for func in func_list:
    print(func(3))

>>>0
>>>3
>>>6

说明:局部名称空间中,查找名称的顺序在函数定义时就已经确定。

下面这种闭包会报错:

def outter():
    a = 1
    def inner():
        a = a + 1
        return a
    return inner

res = outter()
res()


>>>    a = a + 1
UnboundLocalError: local variable 'a' referenced before assignment

说明:在闭包函数inner中,Python将等于号左边的符号视为一个变量,所以inner函数中等于号左边的a是inner函数的局部名称空间的变量。而在=右边时,却使用了a,左边的a+1会先执行然后赋给a,
但是进行a+1的时候,inner会先从局部名称空间中找a这个名称,找到有a,但是这个a是在a+1的后面。程序就会报以上的错。如果局部名称空间没有a,就会往上面的空间找。
再找不到,就会报 a is not defined错误。
原文地址:https://www.cnblogs.com/KbMan/p/11173574.html