Python闭包笔记

首先来看看闭包的概念。

闭包就是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。

将字符串作为返回值大家肯定已经知道了,回过头来,再看一眼第一句话,Python 中一切皆对象,那么字符串和函数应该都一样。如果我将一个函数作为我返回值返回会怎么样呢?

来看一个例子:

1
2
3
4
5
6
7
8
9
def print_msg():
msg = "zen of python"
def printer():
print(msg)
return printer

another = print_msg()
# 输出 zen of python
another()

一般来说,我们在函数中定义的局部变量,在函数执行完就应该不再可用了,但是执行程序我们会发现,程序正常的输出了 msg 变量的内容,这就是闭包的作用了,让局部变量在函数外变得可用。

实际用起来会怎么样呢?

1
2
3
4
5
6
7
8
9
10
def sum1(a):
def add(c):
print(a + c)
return add

sum2 = sum1(1)
sum2(2)
# 3
sum2(4)
# 5

可以看到,执行 sum2(2) 的时候输出了 3,再次执行 sum2(4) 的时候输出了 5,每次的结果都比参数大 1,证明了 a 这个参数在函数执行完成之后没有被销毁,而是在每一次调用函数的时候都被调用了。

装饰器就是闭包的一种应用。

函数属性

每个都有一个 __closure__ 属性,如果是一个函数是闭包的话,它返回的是一个 cell 对象组成的元祖,cell 对象的cell_content 属性就是闭包中的变量。为什么局部变量在函数运行结束还能继续存在并且可以被访问呢?因为它被存储在 cell_content 属性中了。

1
2
3
4
5
6
7
8
9
10
11
12
13
def sum1(a):
def add(c):
print(a + c)
return add

sum2 = sum1(1)
sum2(2)
# 3
print(sum2.__closure__)
print(sum2.__closure__[0].cell_contents)
# 3
# (<cell at 0x0000022DD2AE0C78: int object at 0x000000006A61C6B0>,)
# 1

通过上述代码可以看到,局部变量 1 被存储起来了。

参考资料

https://foofish.net/python-closure.html

本文章首发于个人博客 LLLibra146’s blog
本文作者:LLLibra146
版权声明:本博客所有文章除特别声明外,均采用 © BY-NC-ND 许可协议。非商用转载请注明出处!严禁商业转载!
本文链接https://blog.d77.xyz/archives/4c0cb66.html