闭包
1. 什么是闭包
- 在 python 中创建一个闭包一般有3个要求:
- (1)闭包函数必须有内嵌函数
- (2)内嵌函数必须要引用外层函数的变量
- (3)闭包函数返回内嵌函数的地址(函数名称)
- 作用:可以在不修改目标源码的前提下,加功能
- 注意:闭包函数中的变量的生命周期得到延长
2. 创建一个闭包函数
def funcOut(): name = 'Jery' def funcIn(): # format的简写方式 print(f"姓名 = {name}") return funcIn f = funcOut() f()
运行结果:
姓名 = Jery
3. 判断是否为闭包函数
- 闭包函数相对与普通函数会多出一个__closure__的属性,里面定义了一个元组用于存放所有的cell对象,每个cell对象保存了这个闭包中所有的外部变量。
funcIn.__closure__
:返回None,则不是闭包函数- 如:
def funcOut(): name = 'Jery' def funcIn(): print(f"姓名 = {name}") print(funcIn.__closure__) print(funcIn.__closure__[0].cell_contents) # 第一个外部变量 return funcIn f = funcOut() f()
运行结果
(<cell at 0x000000000272F8B8: str object at 0x00000000026A08B8>,) Jery 姓名 = Jery
装饰器
1. 本质及作用
- 装饰器的本质
- 闭包函数
- 装饰器的作用:
- 在不修改原函数及其调用方式的情况下对原函数功能进行扩展
2. 装饰器的使用
- 装饰器的本质
- 需求:为现有功能fun1增加日志功能
- 传统方案解决 —— 使用闭包
def writeLog(fn): print("记录日志") print('访问方法:'+fn.__name__) def funcOut(func): def funcIn(): writeLog(func) func() return funcIn def fun1(): print("使用功能1") def fun2(): print("使用功能2") fun1 = funcOut(fun1) # 装饰器(闭包) fun1()
-
运行结果:
记录日志 访问方法:fun1 使用功能1
-
使用装饰器(语法糖)解决
def writeLog(fn): print("记录日志") print('访问方法:'+fn.__name__) def funcOut(func): def funcIn(): writeLog(func) func() return funcIn @funcOut def fun1(): print("使用功能1") @funcOut def fun2(): print("使用功能2") fun1() fun2()
运行结果:
记录日志 访问方法:fun1 使用功能1 记录日志 访问方法:fun2 使用功能2
- 传统方案解决 —— 使用闭包
3. 多个装饰器的使用
-
-
如:
-
def war1(func): print("war 1") def inner(*args, **kwargs): print("======war1 start=====") func(*args, **kwargs) # inner print("======war1 end=====") return inner def war2(func): print("war2") def inner(*args, **kwargs): print("======war2 start=====") func(*args, **kwargs) print("======war2 end=====") return inner @war1 @war2 def f(): print("****self****") f()
-
-
- 运行结果:
war2 war1 ======war1 start===== ======war2 start===== ****self**** ======war2 end===== ======war1 end=====
- 运行结果:
-
- 解释:
(1) @war1 @war2 之后相当于 --> f = war1(war2(f)) 其中war2(f)是一个函数,作为实参传递 war2(f): print("======war2 start=====") print("****self****") print("======war2 end=====") war1(war2(f)): print("======war1 start=====") war2(f) print("======war1 end=====") (2) f() 相当于执行 --> war1(war2(f))()
- 解释:
4. 对有参数的函数进行装饰
-
-
def funcOut(fn): print("funcOut") def funcIn(aa, bb): print("funcIn1") fn(aa,bb) print("funcIn2") return funcIn @funcOut def test(a, b): print("a=%d,b=%d" % (a, b)) # 装饰器装饰之后,这不是直接调用test方法,而是调用func_in方法 test(1,2)
结果
-
funcOut funcIn1 a=1,b=2 funcIn2
-
5. 通用装饰器的使用
-
- 一个装饰器可以装饰多个不同参数、不同返回值的函数
- 如:
def funcOut(fn): # 需要有参数,*args,**kwargs def funcIn(*args,**kwargs): print("记录日志") print('访问方法:'+fn.__name__) # 需要有参数,*args,**kwargs # 需要有返回值 return fn(*args,**kwargs) return funcIn # 待装饰函数1:无参数,无返回值 @funcOut def test1(): print("test1") test1() print("---------") # 待装饰函数2:无参数,有返回值 @funcOut def test2(): return "Hello" print(test2()) print("---------") # 待装饰函数3:有参数,无返回值 @funcOut def test3(a): print('a=%d'%a) test3(1) print("---------") # 待装饰函数3:有键值对参数,无返回值 @funcOut def test4(**kwargs): print(kwargs) test4(a=1)
- 结果
记录日志 访问方法:test1 test1 --------- 记录日志 访问方法:test2 Hello --------- 记录日志 访问方法:test3 a=1 --------- 记录日志 访问方法:test3 {'a': 1}