首先通过一例子直观理解一下闭包是什么
实现一个函数avg(),每次调用该函数,传入一个数值,返回历史调用中,所有入参的平均值。
>>> avg(1)
1.0
>>> avg(2)
1.5
>>> avg(3)
2.0
方式一:
class Averager():
def __init__(self):
self.series = []
def __call__(self, new_value):
self.series.append(new_value)
total = sum(self.series)
return total / len(self.series)
avg = Agerager()
avg(1)
avg(2)
avg(3)
这种方式是传统的面向对象的实现方式,python还提供一种闭包的机制可以实现上述功能。
方式二:
def make_averager():
series = []
def averager(new_value):
series.append(new_value)
total = sum(series)
return total / len(series)
return averager
avg = make_averager()
avg(1)
avg(2)
avg(3)
第二种方式,是定义了一个高阶函数,所谓高阶函数就是入参或者返回值为函数的函数。make_averager()的返回值是一个函数,并且该函数是在自己的函数体内定义的。而且还有一点需要注意,就是内部函数averager()中使用了外部函数的局部变量series。被当做返回值的averager就是所谓的闭包。
综上,闭包出现的条件如下:
- 出现函数的嵌套定义。
- 嵌套函数引用了外层函数第一的变量。
- 外层函数返回嵌套函数。
有一点需要注意,为什么make_averager()已经执行完返回了,但averager还能使用make_averager中定义的局部变量呢?
在python中有一个重要的思想:函数是第一对象。所以函数可以像一般的对象一样,可以含有属性。闭包作为一种函数对象,就拥有自己的属性。avg的属性closure中保存着avg可以使用的外层函数的局部变量。这些变量有一个学术上的名字叫自由变量。
可以通过如下方式查看自由变量的值:
>>> avg.__closure__[0].cell_contents
[1, 2, 3]