最近在看 flask的视图装饰器 时,忽然想起预(复)习一下python的装饰器.
这里有一篇比较好的讲解装饰器的书写的 Python装饰器学习(九步入门) .
这里不单独记录装饰器的书写格式了,重点是工作流程.
首先常见的装饰器 格式就是通过@语法糖,简便的写法,让流程有些不太清楚.
装饰器不带参数的情况下:
defdeco(func):
def_deco():
print("beforemyfunc()called.")
func()
print("aftermyfunc()called.")
return_deco
@deco
defmyfunc():
print("myfunc()called.")
myfunc()
运行结果:
beforemyfunc()called.
myfunc()called.
aftermyfunc()called.
myfunc()called.
这个@语法糖的作用是:
defmyfunc():
print("myfunc()called.")
myfunc=deco(myfunc)
也就是现在的myfunc不再是一开始定义的那个了,而变成了
def_deco():
print("beforemyfunc()called.")
func()
print("aftermyfunc()called.")
这一点可以通过
printmyfunc.__name__
而复杂一点的,装饰器带参数的,如:
defdeco(arg="haha"):
def_deco(func):
def__deco():
print("before%scalled[%s]."%(func.__name__,arg))
func()
print("after%scalled[%s]."%(func.__name__,arg))
return__deco
return_deco
@deco()#注意有括号
defmyfunc():
print("myfunc()called.")
@deco("haha1")
defmyfunc1():
print("myfunc()called.")
myfunc()
myfunc1()
实际的操作是,先把装饰进行了运算,即函数deco先被调用
等效于:
def_deco(func):
def__deco():
print("before%scalled[%s]."%(func.__name__,"haha"))# arg ==> "haha"
func()
print("after%scalled[%s]."%(func.__name__,"haha"))# arg ==> "haha"
return__deco
@d_deco#注意没有括号,第一处
defmyfunc():
print("myfunc()called.")
@_deco#这也没括号,第二处
defmyfunc1():
print("myfunc1()called.")
myfunc()
myfunc1()
而参数arg 使用的是默认的"haha
更直观的表达方式就是:
defdeco(arg="haha"):
def_deco(func):
def__deco():
print("before%scalled[%s]."%(func.__name__,arg))
func()
print("after%scalled[%s]."%(func.__name__,arg))
return__deco
return_deco
defmyfunc():
print("myfunc()called.")
defmyfunc1():
print("myfunc()called.")
myfunc=deco()(myfunc)
myfunc1=deco("haha1")(myfunc1)
这时再来看标准库functools中的wraps的使用,比如官网例子:
fromfunctoolsimportwraps
defmy_decorator(f):
@wraps(f)
defwrapper(*args,**kwds):
print'Callingdecoratedfunction'
returnf(*args,**kwds)
returnwrapper
@my_decorator
defexample():
"""Docstring"""
print'Calledexamplefunction'
example()
printexample.__name__
printexample.__doc__
过程就是
defmy_decorator(f):
defwrapper(*args,**kwds):
print'Callingdecoratedfunction'
returnf(*args,**kwds)
wrapper.__name__=f.__name__
wrapper.__doc__=f.__doc__
returnwrapper
example=my_decorator(example)
这样就保留了原函数名称属性和doc,
标准库中函数wraps,可以这样理解:
defwraps(f):
def_f(*args,**kwargs):
f(*args,**kwargs)
_f.__name__=f.__name
_f.__doc__=f.__doc__
return_f
上面的wraps流程可以看出,如果直接使用wraps简直就是f = f(其实不能直接使用),所以一般都是如实例这样包藏在一个装饰器函数内部.
来源:oschina
链接:/u/1755923/blog/495293
如果觉得《python中wraps_python 装饰器及标准库functools中的wraps》对你有帮助,请点赞、收藏,并留下你的观点哦!