1.闭包&装饰器
1.1 闭包
关于函数:
- 当python遇到 def 语句时候 ,会在内存中生成一个函数对象,并且这个函数是靠将函数名来引用,但是这个函数体内部的语句只有在函数的调用的时候才会被执行,而函数调用结束了,就是函数返回时,函数执行完后内部变量将会被回收
- 函数是一个对象,所以可以以对象的形式作为某个函数的结果返回,
闭包:
- 简单来说,外层函数outer()里面包含了一个内部函数 inner(),并且外部函数返回内部函数的对象
def outer(): name = "alex" # 内部函数 def inner(): print(name) return inner fn = outer() # 访问外部函数, 获取到内部函数的函数地址 fn() # 访问内部函数
- 内部函数inner() 存在对外部函数outer()的引用 ,此时这个内部函数 inner()就叫做闭包
- 在闭包中,由于内部函数存在对外部函数变量的引用,所以即使外部函数执行完毕,该变量依然存在但是一定是内层函数调用的外层函数的变量,如果内层函数不会引用,那么这个变量也是不存在的
1.2 装饰器
1.2.1 装饰器的作用
- 装饰器本质上是一个 Python 函数或类,它可以让其他函数或类在不需要做任何代码修改的前提下增加额外功能,
- 装饰器的返回值也是一个函数/类对象。
- 它有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码到装饰器中并继续重用
(1)无参数无返回值的函数
def timer(func): def inner(): print('-函数前添加功能-') func() print('- 函数后添加功能-') return inner #定义一个函数,并添加装饰器 @timer #等价于 func1 = timer(func1) def func1(): print('func1')
#函数执行结果
# -函数前添加功能-
# func1
# -函数后添加功能-
(2)有参数有返回值的函数
def wrapper(func): def inner(*args,**kwargs): print('--函数前添加功能--') ret = func(*args,**kwargs) print('--函数后添加功能--') return ret return inner #定义一个函数,并添加装饰器 @wrapper #等价于 func1 = timer(func1) def func1(m): print('--func1--') return m #调用函数 f = func1(20) print(f)
1.2.3 带有参数的装饰器
def outer(flag): def timer(func): def inner(*args,**kwargs): if flag: print('--添加功能--') ret = func(*args,**kwargs) else: ret = func(*args,**kwargs) return ret return inner return timer #定义函数并添加装饰器 @outer(True) # func1 = timer() def func1(m): print('--func1--') return m #调用函数 print(func1(20))
#--添加功能--
#--func1--
#20
1.2.4 多个装饰器装饰一个函数
def wrapper1(func): print('--wrapper1装饰--') def inner1(*args,**kwargs): print('--wrapper1 前--') ret = func(*args,**kwargs) print('--wrapper1 后--') return ret return inner1 def wrapper2(func): print('--wrapper2装饰--') def inner2(*args,**kwargs): print('--wrapper2 前--') ret = func(*args,**kwargs) print('--wrapper2 后--') return ret return inner2 #定义函数并添加装饰器 @wrapper2 #func1 = wrapper2(func1) inner2 func = inner1 @wrapper1 #func1 = wrapper1(func1) inner1 func = func1 def func1(m): print ('--func1--') return m #调用函数 print(func1(20)) #执行结果: # --开始装饰wrapper1-- # --开始装饰wrapper2-- # --wrapper2 前-- # --wrapper1 前-- # --func1-- # --wrapper1 后-- # --wrapper2 后-- # 20
#注:
- 装饰器在代码写完后,此时不用调用函数,就会进行装饰
- 函数装饰时,会先执行离函数最近的装饰器
- 当调用函数时,函数会先执行离函数最远的装饰器再执行离的近的装饰器,再执行函数本身
1.2.5 装饰器修复技术
import time from functools import wraps def timer(func): @wraps(func) def inner(): print(time.time()) ret = func() return ret return inner
另外:可以通过functools使得打印名字为函数原本名
import functools def wrapper(func): @functools.wraps(func) def inner(*args, **kwargs): return func(*args, **kwargs) return inner @wrapper def f1(): print('f1') @wrapper def f2(): print('f1') print(f1.__name__) print(f2.__name__)