chapter5.2装饰器
Posted rprp789
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了chapter5.2装饰器相关的知识,希望对你有一定的参考价值。
装饰器
有一个需求,将一个加法函数,增加一个功能,输出调用的参数,及调用信息
在源代码里插入代码,叫硬编码,不利于更改。非业务功能输出信息,不应该放在业务代码里。
def add(x,y): """ function add """ return x+y def logger(fn,*args,**kwargs): print(‘sdfasd‘) ret = fn(*args,**kwargs) return ret print(logger(add,4,5))
定义两个函数,调用后加强输出,但是函数传参是个问题,使用以上方法,*args和**kwargs
将函数柯里化
def logger(fn): def wn(*args,**kwargs): print(‘Function is {}‘.format(wn.__name__)) wee = fn(*args,**kwargs) return wee return wn def add(x,y): """ function add """ return x+yprint(logger(add,4,5))
装饰器语法糖
def logger(fn): def wn(*args,**kwargs): print(‘Function is {}‘.format(fn.__name__)) wee = fn(*args,**kwargs) return wee return wn @logger ##==>add = logger(add) def add(x,y): """ function add """ return x+y ret = add(4,4) print(ret)
装饰器(无参)
是一个函数,函数作为形参,返回值也是函数,可以使用@Functionname方式调用
以上总结不准确,只是方便理解
装饰器就是高阶函数,但装饰器是对传入函数的功能的增强(装饰)
add = logger(add)
这句中函数被重新覆盖,但是原来的add指向的地址被logger中的fn引用,仍然存在。这里fn使用了闭包
def logger(fn): def wrap(*args,**kwargs): ‘‘‘This is a warp‘‘‘ # print(‘function is {}‘.format(fn.__name__)) print(‘doc: {}‘.format(fn.__doc__)) ret = fn(*args,**kwargs) # return ret return wrap @logger def add(x,y): ‘‘‘This is a function of addition‘‘‘ return x+y ret = add(4,5) print(ret,add.__doc__)
这里可以调用fn.__doc__查看文档属性,想要看原来add的文件属性,在全局只能看到logger的,python中提供有相应的函数,要是自己实现,可以使用两层装饰器。外层可以使用带参函数
带参装饰器
def copy(src): def copy_inner (dst): dst.__name__ = src.__name__ dst.__doc__ = src.__doc__ return dst return copy_inner def logger(fn): @copy(fn)####wrap = copy(fn)(wrap) def wrap(*args,**kwargs): ‘‘‘This is a warp‘‘‘ # print(‘function is {}‘.format(fn.__name__)) print(‘doc: {}‘.format(fn.__doc__)) ret = fn(*args,**kwargs) # return ret return wrap @logger###add = logger(add) def add(x,y): ‘‘‘This is a function of addition‘‘‘ return x+y ret = add(4,5) print(ret,add.__doc__)
以上函数,copy函数修饰了logger,将函数add的属性复制到了函数warp上,只复制了名字和文档的属性
要想全部覆盖,可以使用wrapper函数
from functools import wraps functools类下的wraps方法
functools.update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=(‘__dict__‘,))
类似于copy_properties功能
wrapper包装函数,被更新者,wrapper被包装函数,数据源
元组WRAPPER__ASSIGNMENTS中是要覆盖的属性
(‘__module__‘, ‘__name__‘, ‘__qualname__‘, ‘__doc__‘, ‘__annotations__‘)
模块名,名称,限定名,文档,参数注解
元组WRAPPER_UPDATES中是要被更新的属性,__dict__属性字典
增加一个__wrapper__属性,保留wrapped的属性
import functools def logger(fn): def wrap(*args,**kwargs): ‘‘‘This is a warp‘‘‘ print(‘function is {}‘.format(fn.__name__)) print(‘doc: {}‘.format(fn.__doc__)) ret = fn(*args,**kwargs) return ret return functools.update_wrapper(wrap,fn) @logger###add = logger(add) def add(x,y): ‘‘‘This is a function of addition‘‘‘ return x+y ret = add(4,5) print(ret,add.__doc__)
@functools.wraps( wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)
wrapped 被包装函数
import functools def logger(fn): @functools.wraps(fn)###==>wrap = wraps(fn)(wrap) def wrap(*args,**kwargs): ‘‘‘This is a warp‘‘‘ print(‘function is {}‘.format(fn.__name__)) print(‘doc: {}‘.format(fn.__doc__)) ret = fn(*args,**kwargs) return ret return wrap @logger###add = logger(add) def add(x,y): ‘‘‘This is a function of addition‘‘‘ return x+y ret = add(4,5) print(ret,add.__doc__)
以上是关于chapter5.2装饰器的主要内容,如果未能解决你的问题,请参考以下文章