现有如下函数:
def fun1(): print('...fun1()...')def fun2(): print('...fun2()...')#调用函数fun1()fun2()
需求:需要给以上两个函数添加记录日志功能
方法一:函数调用
def logging(): print('...logging...')def fun1(): print('...fun1()...') logging()def fun2(): print('...fun2()...') logging()#调用函数fun1()fun2()
分析:上面这种方式适合少量函数调用,如果有n个地方需要调用logging()函数,那么得手动调用n次,比较麻烦,而且在fun1()中调用loggin()也相当于修改了fun1()的内容。
方法二:高阶函数(函数名作为参数传递给另一个函数)
def logging(fun): fun() print('...logging...')def fun1(): print('...fun1()...')def fun2(): print('...fun2()...')#调用函数logging(fun1)logging(fun2)
分析:该方法是高阶函数的用法,将函数名当做参数传递给另一个函数,优点是没有修改源代码,缺点是该方法修改了调用的方式。
方法三:高阶函数(返回值中包含函数名)
def logging(fun): print('...logging...') return fundef fun1(): print('...fun1()...')def fun2(): print('...fun2()...')#调用函数fun1 = logging(fun1)fun2 = logging(fun2)fun1()fun2()
分析:该方法的优点是没有改变原有函数的调用方式,但是改变的原有输出顺序。
方法四:嵌套函数
def logging(fun): def dec(fun): return fun() dec(fun) print('...logging...')def fun1(): print('...fun1()...')def fun2(): print('...fun2()...')#调用函数logging(fun1)logging(fun2)
分析:该方法优点是没有修改源代码,但是调用方式改变了。
总结:
如果需要不修改源代码、不修改调用方式,则需要使用高阶函数+嵌套函数一起,由此引入了装饰器的概念。
装饰器
定义:本质是函数(装饰其他函数),就是为其他函数添加附加功能。
原则:1.不能修改被装饰函数的源代码
2.不能修改被装饰函数的调用方式
装饰器知识储备:
1.函数即“变量”
2.高阶函数
a:函数名作为实参传给另一个函数(在不修改源代码的情况下为其新增功能) b:返回值中包含函数名(不修改函数的调用方式)3.嵌套函数
高阶函数+嵌套函数=>装饰器
使用高阶函数+嵌套函数修改上面需求:
def logging(fun): def dec(): fun() print('...logging...') return decdef fun1(): print('...fun1()...')def fun2(): print('...fun2()...')#调用函数fun1 = logging(fun1)fun2 = logging(fun2)fun1()fun2()
装饰器语法糖:即在函数前使用@函数名
使用语法糖修改以上代码:
def logging(fun): def dec(): fun() print('...logging...') return dec@loggingdef fun1(): print('...fun1()...')@loggingdef fun2(): print('...fun2()...')#调用函数fun1()fun2()
如上案例中的@logging可以理解为:fun1 = logging(fun1)
案例:无参装饰器与有参装饰器
无参装饰器:
def fun(func): def dec(): func() print('...新增功能...') return dec@fundef foo(): print('...test1()...')foo()
def fun(func): def dec(x,y): func(x,y) print('...新增功能...') return dec@fundef foo(x,y): print(x+y) print('...test1()...')foo(5,3)
有参装饰器:
def out_fun(m,n): def in_fun(fun): def dec(x,y): fun(x,y) print('...新功能...') print("m*n=%s"%(m*n)) return dec return in_fun@out_fun(2,6)def foo(x,y): print(x+y) print('...test1()...')foo(5,3) # out_fun(2,6)(foo)(5,3)'''8...test1()......新功能...m*n=12'''