通过我们的python柯里化就能学习装饰器啦~!
装饰器应该是目前来说学到的比较困难的,非常非常重要,下面根据代码演化出装饰器
需求:
一个加法函数,想增强它的功能,能够输出被调用过以及调用的参数信息
def add(x, y, file): print("call {}, {} + {}".format(add.__name__, x, y), file=file) """" __name__是一个特殊的属性,将日志输出到控制台 print函数后面其实还可以跟file,将输出信息输出到其它地方,比如d:/123 """ return x + yprint(add(4, 5))
上面的加法函数是完成了需求,但是有以下的缺点:
打印语句的耦合太高;
加法函数属于业务功能,而输出信息的功能,属于非业务功能代码,不该放在业务函数加法中;
这种写法有种称呼叫做侵入式代码;
想一下想要对函数的功能进行增强怎么办呢?如何做到业务功能离?
def add(x, y): return x + ydef logger(function): print('-------begin-----')# 增强的输出 x = function(4, 5)# 相当于x = add(4, 5) print('------end--------')# 增强的功能 return xprint(logger(add))
上面代码做到了业务功能分离,但是x = function(4, 5)这里会有问题,这里被写死了?该如何做呢?
def add(x, y): return x + ydef logger(function, x, y): print('-------begin-----') x = function(x, y) print('------end--------') return xprint(logger(add))
这样能做到,但是还是有问题,如果我的函数是这样写的,怎么办?
def add1(x, y): return x + ydef add2(x, y, z): return x + y + zdef logger(function, x, y):# x, y这里写死肯定不行啦 print('-------begin-----') x = function(x, y) print('------end--------') return xprint(logger(add1))print(logger(add2)) ####
怎么搞定呢?
def add1(x, y): return x + ydef add2(x, y, z): return x + y + zdef add3(x, y, *args, z): return x + y + zdef logger(function, *args, **kwargs): print('-------begin-----') x = function(*args, **kwargs) print('------end--------') return xprint(logger(add1, 4, 5))print(logger(add2, 4, 5, 6))print(logger(add3, 4, z=5, y=6))
试想还能不能在变化一下?(柯里化)
def add1(x, y): return x + ydef add2(x, y, z): return x + y + zdef add3(x, y, *args, z): return x + y + zdef logger(function): def _logger(*args, **kwargs): print('-------begin-----') x = function(*args, **kwargs) print('------end--------') return x return _loggerfoo = logger(add1)print(foo(10, 20))
如果把foo = logger(add1)换成add1 = logger(add1),这样会不会报错?
不会报错,那么就有更简单的方式了———装饰器
def logger(function): def _logger(*args, **kwargs): print('-------begin-----') x = function(*args, **kwargs) print('------end--------') return x return _logger@logger # 这句相当于 add1 = logger(add1)def add1(x, y): return x + yprint(add1(4, 5))
这就是装饰器函数.
@logger这句是语法糖,相当于add1 = logger(add1),所以当最后一句print(add1(4,5)),这里调用的add1相当于调用的是logger函数
的内层函数,跟def add1(x, y)这句没有关系了
这就是装饰器的演化,但是前面几个技术需要熟悉掌握,比如传参,解构的技巧
注意规范:
外层函数要返回内层函数的引用;
外层函数至少传入一个参数,这个参数应该是要被包装的一个函数;
既然是包装原函数,就不能被改造;