闭包
什么是闭包:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包。
需要满足的条件
1.一个函数内嵌套一个函数
2.外部函数的返回值必须是这个内部的函数
3.内部函数必须使用外部函数中的局部变量
def fun_1():
num_1=9
def fun_2(num_2):
print(num_1+num_2)
return fun_2
f=fun_1() #现在f=fun_2
f(8) #fun_2(8)
输出 17
这时就称fun_2为闭包
由于闭包引用了外部函数的局部变量,则外部函数的局部变量没有及时释放
def fun_2():
a=list()
def fun(num):
a.append(num)
print(num)
return a
return fun
g1=fun_2()
g2=g1(2)
print('****',g2)
g3=g1(3)
print('*****',g3)
输出结果
2
**** [2]
3
***** [2, 3]
当执行fun_2函数时,变量a被创建。执行g1(2)时,列表a添加一个值2。执行g2(3)时,列表a又添加了一个值。我们知道一个函数内的局部变量的生命周期是从执行函数开始到到结束。而现在我们函数已经执行完了,按道理来讲局部变量a应该清除才对。这就是因为闭包的原因,上面也说了闭包使用了外部函数的局部变量,这就导致局部变量a一直在内存中无法释放,
占用内存。
为什么使用闭包?
闭包就是为了不懂原函数的代码,还要给它增加新功能的一个手段
通过外面的一层层函数传递的参数,让最内层函数直接调用外层函数的代码,增加了新的功能。
优点:闭包优化了变量,原来需要类对象完成工作,闭包也可以完成
缺点:由于闭包引用了外部函数的局部变量,则外部函数的局部变量 没有完全释放,占用内存。
装饰器
定义:装饰器本身是一个可调用对象,接收一个函数作为参数,然后将其返回或替换成另一个函数或可调用对象。可以理解成,原来那是一堵白墙,经过了一层装饰,这层装饰可能是漆也可能把墙掏空镶进一层黄金变得金光闪闪,最后呈现在你眼前的就是装饰后的样子。
可以把它完全当成常规函数来调用,其参数是另一个函数。装饰器有两大特征,一是能把被装饰的函数替换成其他函数,二是装饰器在加载函数时立即执行。
def read_oil(func):
print("ready to paint!")
def red_wall_func():
print("red wall")
return red_wall_func
@read_oil
def wall():
print("wall!")
if __name__=="__main__":
print("start painting")
wall()
输出
ready to paint!
start painting
red wall
可以看出,装饰器 red_oil
将函数 wall
替换成了另一个函数,就好比在原来的墙上刷了一层红漆。而装饰器在被装饰的函数被定义时立即执行,而被装饰的函数在运行的时候才执行,这也是导入时和运行时的区别。
函数中变量的作用范围
red_paint="red oil"
def wall(paint):
print(paint)
global red_paint
print(red_paint)
if __name__ == '__main__':
wall("yelloow oil")
输出
yelloow oil
red oil
nonlocal 声明
nonlocal
声明,作用是将变量标记为自由变量,也就意味着我们可以对做了 nonlocal
声明的变量进行修改
def wall():
nums=0
oils=[]
def paint_wall(color):
nonlocal nums
nums +=1
oils.append(color)
print("Paint wall by color:"+color)
print("Paint wall {} times".format(nums))
return oils
return paint_wall
if __name__ == '__main__':
white_wall=wall()
white_wall("red")
white_wall("yellow")
输出
Paint wall by color:red
Paint wall 1 times
Paint wall by color:yellow
Paint wall 2 times
带参数的装饰器
既然装饰器本质上就是一个函数,那装饰器也可以传参。那么具体应该怎么做呢?在 Python 中需要建立一个装饰器工厂函数,把参数传给它,再返回一个装饰器,然后应用到要装饰的函数上。