合规国际互联网加速 OSASE为企业客户提供高速稳定SD-WAN国际加速解决方案。 广告
### 什么是闭包 函数身为第一类对象,它可以作为函数的返回值返回,现在我们来考虑如下的例子: ~~~python def print_msg(): # print_msg 是外围函数 msg = "zen of python" def printer(): # printer 是嵌套函数 print(msg) return printer another = print_msg() # 输出 zen of python another() ~~~ 看完这个例子,我们再来定义闭包,维基百科上的解释是: > 在计算机科学中,闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。 > 所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。 这里的 another 就是一个闭包,闭包本质上是一个函数,它有两部分组成,printer 函数和变量 msg。闭包使得这些变量的值始终保存在内存中。 闭包,顾名思义,就是一个封闭的包裹,里面包裹着自由变量,就像在类里面定义的属性值一样,自由变量的可见范围随同包裹,哪里可以访问到这个包裹,哪里就可以访问到这个自由变量。 * 闭包 --> 为内层函数提供了运行环境 ### 为什么要使用闭包 闭包避免了使用全局变量,此外,闭包允许将函数与其所操作的某些数据(环境)关连起来。这一点与面向对象编程是非常类似的,在面对象编程中,对象允许我们将某些数据(对象的属性)与一个或者多个方法相关联。 一般来说,当对象中只有一个方法时,这时使用闭包是更好的选择。来看一个例子: ~~~python def adder(x): def wrapper(y): return x + y return wrapper adder5 = adder(5) # 输出 15 adder5(10) # 输出 11 adder5(6) ~~~ 这比用类来实现更优雅,此外装饰器也是基于闭包的一种应用场景。 所有函数都有一个 \_\_closure\_\_属性,如果这个函数是一个闭包的话,那么它返回的是一个由 cell 对象 组成的元组对象。cell 对象的cell\_contents 属性就是闭包中的自由变量。 ~~~python >>> adder.__closure__ >>> adder5.__closure__ (<cell at 0x103075910: int object at 0x7fd251604518>,) >>> adder5.__closure__[0].cell_contents 5 ~~~ 这解释了为什么局部变量脱离函数之后,还可以在函数之外被访问的原因的,因为它存储在了闭包的 cell\_contents中了。