函数闭包(closure)机制

python中的闭包(closure)是指一个函数内部又嵌套了一个函数,内层函数可以使用外层函数的参数和局部变量,外层函数返回内层函数的引用。
一般来说,一个函数的实参及局部变量,只在函数执行过程中存储,函数执行完后就会释放掉。 但闭包机制的这种外层函数执行完后,由于其内层函数需要用到外层的数据,所以python会将这些数据持久化保存。相当于把内层函数,及其用到的外部变量打包在一块放在一个封闭的空间里,这个空间我们就称其为闭包。

每次执行外部函数时,都会生成一个独立的闭包,而非共享同一个存储空间。

def outter():
    data = []
    def inner(value):
        data.append(value)
        return data
    data=[0]
    return inner

f = outter()
print(f(1))
print(f(2))
print(f(3))
print(f.__closure__)  # 对于一个闭包,函数用到的外部数据存放在 __closure__ 中
print(hex(id(f(1))))  # 可以看出,闭包中返回的外部数据data的id与存放在__closure__中的data变量的id是相同的。

print('-' * 25, '分隔线','-' * 25)

g = outter()  # g与f是两个独立的闭包,使用各自的外部数据data
print(g(1))
print(g(2))
print(g.__closure__)
print(hex(id(g(1))))

输出结果:
[0, 1]
[0, 1, 2]
[0, 1, 2, 3]
(<cell at 0x000002664B0B7FD0: list object at 0x000002664B057540>,)
0x2664b057540
------------------------- 分隔线 -------------------------
[0, 1]
[0, 1, 2]
(<cell at 0x000002664B0B7F40: list object at 0x000002664B0CEC80>,)
0x2664b0cec80

上面示例中,外层函数data是一个列表,内层函数使用append方法对其内容进行追加, 这是因为列表是可变类型(mutable)的变量
但如果是一个immutable类型的变量,内层函数如果通过赋值语句来修改外层变量的值其实是做不到的(直接使用赋值语句的话相当于在内层函数里定义了一个自己的局部变量,就与外层函数不相关了),这时的赋值语句相当于在内导函数内部又定义了一个新的局部变量并与外层函数的局部变量同名。
这时如果想要让内层函数修改外层函数变量的值,需要加nonlocal语句。

def outter():
    data = 10
    def inner(value):
        nonlocal data
        data += value  # 如果没有上面一行的nonlocal语句,这行是会报错的。
        return data
    return inner

f = outter()
print(f(1))
print(f(2))
print(f(3))
print(f.__closure__)  # 对于一个闭包,函数用到的外部数据存放在 __closure__ 中
print(hex(id(f(1))))  # 可以看出,闭包中返回的外部数据data的id与存放在__closure__中的data变量的id是相同的。

print('-' * 25, '分隔线','-' * 25)

g = outter()  # g与f是两个独立的闭包,使用各自的外部数据data
print(g(1))
print(g(2))
print(g.__closure__)
print(hex(id(g(1))))

输出结果:
11
13
16
(<cell at 0x00000188A1077FD0: int object at 0x00007FF883E4E508>,)
0x7ff883e4e528
------------------------- 分隔线 -------------------------
11
13
(<cell at 0x00000188A1077F40: int object at 0x00007FF883E4E4A8>,)
0x7ff883e4e4c8

顺便说一下nonlocalglobal这两个关键字的区别。
作用域不同global 关键字指向的是模块级别的变量,而 nonlocal 指向的是最近一层的非局部变量,通常是外层函数中的变量。
适用场合不同global 通常用于需要在函数中修改全局变量的情况;而 nonlocal 则用于需要在嵌套函数中修改外层函数变量的情况。

posted @ 2024-11-26 10:46  RolandHe  阅读(21)  评论(0编辑  收藏  举报