python | 闭包
python | 闭包
基础
作用域
作用域是程序运行时变量可被访问的范围,定义在函数内的变量是局部变量,局部变量的作用范围只能是函数内部范围内,它不能在函数外引用。
定义在模块最外层的变量是全局变量,它是全局范围内可见的,当然在函数里面也可以读取到全局变量的。例如:
num = 10 # 全局变量
def foo():
print(num) # 10
而在函数外部则不可以访问局部变量。
def foo():
num = 10
print(num) # NameError: name 'num' is not defined
嵌套函数
定义在函数里面的函数称之为嵌套函数(nested function)
def outer(): # outer是外层函数
msg = "python"
def inner(): # inner 为内层函数即嵌套函数
print(msg)
return inner()
outer() # 输出 python
对于嵌套函数,它可以访问到其外层作用域中声明的非局部(non-local)变量。首先查找本层函数 inner 内部是否有定义,没有发现后开始查找外层作用域的变量
msg = "global"
def outer(): # outer是外层函数
# msg = "python"
def inner(): # inner 为内层函数即嵌套函数
print(msg)
return inner()
outer()
而当把 outer函数的变量注释后,在全局进行定义,此时就开始查找全局变量
python 中函数是可以作为变量进行引用的,类似高中数学中的 f(x)计算
在高中数学复合函数定义中:
y=f(u), u=g(x),则函数 y=f(g(x))为复合函数,f(u)为外层函数,g(x)为内层函数,u为中间变量
计算顺序应当是先计算内层函数然后结果作为变量来计算外层函数
闭包
def outer(): # outer是外层函数
msg = "python"
def inner(): # inner 为内层函数即嵌套函数
print(msg)
return inner # 返回 inner 的地址
result = outer()
result() # 输出 python
print(outer()) # 输出 inner的内存地址
print(outer()()) # 输出 python和 None
print(result.func_closure)
结果
python
<function outer.<locals>.inner at 0x103136ea0>
python
None
闭包使得局部变量在函数外被访问成为可能。 return 的函数不加括号返回的是地址。func_closure
打印了闭包中包含了哪些外部变量。
每个函数都有__closure__
属性,如果一个函数是闭包的话则会返回一个由 cell 对象组成的元组对象。而 cell 对象的cell_contents
属性就是闭包中保存的自由变量
def adder(x):
def wrapper(y):
return x + y
return wrapper # 返回函数地址
adder5 = adder(5)
adder5(10) # 输出 10
adder5(6) # 输出 11
print(adder.__closure__)
print(adder5.__closure__)
print(adder5.__closure__[0].cell_contents)
结果
None
(<cell at 0x106430fd8: int object at 0x1050cf110>,)
5 # 自由变量
闭包特点
一个函数返回的函数对象,这个函数对象执行的话依赖非函数内部的变量值,这个时候,函数返回的实际内容如下:
- 函数对象
- 函数对象需要使用的外部变量和变量值
以上就是闭包
闭包必须嵌套在一个函数里,必须返回一个调用外部变量的函数对象,才是闭包
最后推荐一个python 可视化运行的网站,对于 python 执行的步骤和存储的变量等很直观
http://www.pythontutor.com/visualize.html#mode=display
参考:
https://www.cnblogs.com/xiaxiaoxu/p/9785687.html
https://zhuanlan.zhihu.com/p/26934085