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打印了闭包中包含了哪些外部变量。
enter description here

每个函数都有__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 # 自由变量

闭包特点

一个函数返回的函数对象,这个函数对象执行的话依赖非函数内部的变量值,这个时候,函数返回的实际内容如下:

  1. 函数对象
  2. 函数对象需要使用的外部变量和变量值
    以上就是闭包

闭包必须嵌套在一个函数里,必须返回一个调用外部变量的函数对象,才是闭包

最后推荐一个python 可视化运行的网站,对于 python 执行的步骤和存储的变量等很直观
http://www.pythontutor.com/visualize.html#mode=display

参考:
https://www.cnblogs.com/xiaxiaoxu/p/9785687.html
https://zhuanlan.zhihu.com/p/26934085

原文地址:https://www.cnblogs.com/hbgzy/p/10971562.html