1 """
2 概念:闭包是指延伸了作用域的函数,其中包含函数定义体的引用但是不在定义体中定义的非全局变量。主要是指它能够访问定义体之外
3 的非全局变量。主要是在嵌套函数中可能涉及到。
4 下面是计算历史均值的两种实现方法,通过这两种实现方法来通过示例讲清楚闭包
5 """
6 #使用类实现求历史平均值的方法
7 class avg_class():
8 def __init__(self):
9 self.history_num = []
10 def __call__(self, num): #类的call方法可以理解为实例默认的调用方法,即直接使用实例名不加.方法名,实例可以像函数一样传参并调用
11 self.history_num.append(num)
12 current_sum = sum(self.history_num)
13 return current_sum/len(self.history_num)
14 avg = avg_class()
15 print(avg(10)) #10.0 调用__call__方法
16 print(avg(11)) #10.5
17 print(avg(12)) #11.0
18
19 #使用嵌套函数实现历史平均值方法
20 def make_avg():
21 history_num = []
22 def cal_avg(num):
23 history_num.append(num)
24 current_sum = sum(history_num)
25 return current_sum/len(history_num)
26 return cal_avg
27 avg = make_avg()
28 print(avg(10)) #10.0
29 print(avg(11)) #10.5
30 print(avg(12)) #11.0
31
32 #输出avg的变量和自由变量;函数的code属性保存着变量和自由变量信息;closure中保存着history_num的绑定,closure各元素对应
33 # co_freevars中的一个名称,cell_contents保存着真正的值
34 print(avg.__code__.co_varnames) #('num', 'current_sum')
35 print(avg.__code__.co_freevars) #('history_num',)
36 print(avg.__closure__) #(<cell at 0x034538D0: list object at 0x0345A8F0>,)
37 print(avg.__closure__[0].cell_contents) #[10, 11, 12]
38
39 """
40 使用类实现求历史平均值我们能够明确的知道历史数据存在实例的history_num属性内,我们只要对实例的这个属性进行操作
41 就能够获取我们需要的结果。
42 但是使用嵌套函数实现的求历史平均值这些历史数据存在哪里呢?当make_avg函数执行完毕以后其内部定义的history_num
43 作为局部变量,其生命周期应该伴随函数的调用而消亡,实际程序运行并未报错且从程序结果来看history_num在make_avg
44 调用完毕后仍然能够正常被调用。
45 在cal_avg函数中history_num是自由变量,指未在本地作用域中绑定的变量
46 综上闭包是一种函数,它会保留定义函数时存在的自由变量的绑定(即上述嵌套函数中的history_num),这样调用函数时
47 虽然定义作用域不可用了,但是仍然能够使用这些绑定。 cal_avg的闭包包括cal_avg定义本身还包含history_num = []语句
48 """