闭包是什么?小菜很难用一句话说明或者用白话文概括。我们先看看其他语言是怎么定义闭包的。

ECMAScript中给闭包的定义是:闭包,指的是词法表示包括不被计算的变量的函数,也就是说,函数可以使用函数之外定义的变量。

维基上的解释: 在计算机科学中,闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。

不知道大家看到上面那些概念是什么反应,反正我觉得词很拗口还很难懂,他们站在专业的角度给出闭包的定义。

参考文章:

1.造成闭包的原因

在python中造成闭包的原因,个人认为是作用域造成的。我们用闭包写一个y = 5x + 3的函数

def closure():
    x = 5
    b = 3
    def curve(a):
        return a * x + 3
    return curve
y = closure()
>>> y(1)
8
>>> y(2)
13

python 中有全局变量局部变量类变量。在函数外部不能访问函数内部变量,但是函数内部可以访问外部变量。上面列子中,我们在cloosure函数外部是肯定不能访问x,b的值。在计算机中,调用函数执行完后就会销毁,当我们调用closure函数后,返回了curve函数实体。curve实体中的xb变量并未被销毁,而是保存了下来。curve函数就形成了一个闭包,因此xb变量的生命周期被延续下来。

2.为什么使用闭包

闭包避免了使用全局变量,此外,闭包允许将函数与其所操作的某些数据(环境)关连起来。这一点与面向对象编程是非常类似的,在面对象编程中,对象允许我们将某些数据(对象的属性)与一个或者多个方法相关联。

一般来说,当对象中只有一个方法时,这时使用闭包是更好的选择。来看一个例子:

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 属性就是闭包中的自由变量。

>>> adder.__closure__
>>> adder5.__closure__
(<cell at 0x103075910: int object at 0x7fd251604518>,)
>>> adder5.__closure__[0].cell_contents
5

python3.7 入门教程

Python 准备工作(1) Python 基本数据类型 Number(2) Python 字符串 str(3) Python 列表List(4) Python 元组tuple(5) Python 集合set(6) Python 字典 dict(7) Python 变量(8) Python 运算符(9) Python 条件语句(10) Python 循环语句(11) Python 包 模块(12) Python 函数一(13) Python 函数二(14) Python 面向对象(15) Python 正则(16) Python json(17) Python 枚举(18) Python 闭包(19) Python 装饰器(20) Python 杂记(21) Python with(22)