闭包的定义:
首先我们先给出闭包的概念,如果内部函数引用了外部函数作用域里的变量(非全局变量),则称这个内部函数以及用到的变量统称为闭包。
在python中的闭包需要满足三个条件:
- 必须是一个嵌套的函数。
- 外层函数返回的是内层函数的函数名
- 嵌套函数必须引用一个外部的非全局的局部自由变量。
可能这些东西听起来非常绕嘴,难以理解,下面我们举个例子。
def func_out(num): #外层函数
# 在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包
def func_in(num_in): #内层函数
print("在内层函数里, num_in is %d" % num_in)
return num + num_in
# 其实这里返回的就是闭包的结果
return func_in #这里返回就是内层函数名字func_in
# 给func_out函数赋值,这个20就是给参数num
pnum = func_out(20)
# 注意 这里的100其实给参数numb_in
print(pnum(100))
#注 意这里的200其实给参数numb_in
print(pnum(200))
让我们看看运行的结果:
在内层函数里, num_in is 100
120
在内层函数里, num_in is 200
220
在开发中,用到闭包可以提高的代码的复用率。下面我们举一个初中曾经学习的一次函数y=kx+b的例子
def line_conf(k, b): #外层函数 发生函数嵌套
def line(x): #内层函数
return k*x + b #内层函数引用外层函数的变量 ,格式:y=kx+b
return line #返回内层函数名
line1 = line_conf(2, 1) # k=2 , b=1 -->y=2x+1
print(line1(7)) # y=7*2+1=15
line2 = line_conf(4, 5) # k=4, b=5 -->y=4x+5
print(line2(8)) # y=4*8+5=37
上面的代码中,函数line与变量a,b构成闭包。在创建闭包的时候,我们通过line_conf的参数a,b说明了这两个变量的取值,这样,我们就确定了函数的最终形式(y = 2x + 1和y = 4x + 5)。
我们只需要变换参数a,b,就可以获得不同的一次函数的表达式。由此,我们可以看到,闭包也具有提高代码可复用性的作用。
如果没有闭包,我们需要每次创建直线函数的时候同时说明a,b,x。这样,我们就需要更多的参数传递,也减少了代码的可移植性。
除此之外,闭包也可以做装饰器用,比如计算某一个函数的运行时间
import time
def timer(func):
def wrapper():
start_time = time.time() #开始时间
func() #引用外层函数中的变量
stop_time = time.time() #结束时间
print('run time is %f'%(stop_time-start_time))
return wrapper
@timer #定义修饰timer为装饰器
def fun():
print('函数开始start-----')
time.sleep(3) #函数睡眠3秒钟
print('函数结束end-------')
if __name__ == '__main__':
fun()
看看运行的结果:
函数开始start-----
函数结束end-------
run time is 3.000939
下面我们总结点闭包的优点:
- 避免使用全局变量
- 提高了代码的复用率
- 实现部分数据的隐藏
- 可以提供更优雅的面向对象实现
闭包的缺点:
- 消耗内存空间,造成内存泄漏 (因为内部引用外层的局部变量,没有及时释放)
参考文献:
Python中的闭包