【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
最近在看 flask的视图装饰器 时,忽然想起预(复)习一下python的装饰器.
这里有一篇比较好的讲解装饰器的书写的 Python装饰器学习(九步入门) .
这里不单独记录装饰器的书写格式了,重点是工作流程.
首先常见的 装饰器 格式就是通过@语法糖,简便的写法,让流程有些不太清楚.
装饰器不带参数的情况下:
def deco(func):
def _deco():
print("before myfunc() called.")
func()
print(" after myfunc() called.")
return _deco
@deco
def myfunc():
print(" myfunc() called.")
myfunc()
运行结果:
before myfunc() called.
myfunc() called.
after myfunc() called.
myfunc() called.
这个@语法糖的作用是:
def myfunc():
print(" myfunc() called.")
myfunc = deco(myfunc)
也就是现在的myfunc不再是一开始定义的那个了,而变成了
def _deco():
print("before myfunc() called.")
func()
print(" after myfunc() called.")
这一点可以通过
print myfunc.__name__
而复杂一点的,装饰器带参数的,如:
def deco(arg="haha"):
def _deco(func):
def __deco():
print("before %s called [%s]." % (func.__name__, arg))
func()
print(" after %s called [%s]." % (func.__name__, arg))
return __deco
return _deco
@deco()#注意有括号
def myfunc():
print(" myfunc() called.")
@deco("haha1")
def myfunc1():
print(" myfunc() called.")
myfunc()
myfunc1()
实际的操作是,先把装饰进行了运算,即函数deco先被调用
等效于:
def _deco(func):
def __deco():
print("before %s called [%s]." % (func.__name__, "haha"))# arg ==> "haha"
func()
print(" after %s called [%s]." % (func.__name__, "haha"))# arg ==> "haha"
return __deco
@d_deco#注意没有括号,第一处
def myfunc():
print(" myfunc() called.")
@_deco#这也没括号,第二处
def myfunc1():
print(" myfunc1() called.")
myfunc()
myfunc1()
而参数arg 使用的是默认的"haha
更直观的表达方式就是:
def deco(arg="haha"):
def _deco(func):
def __deco():
print("before %s called [%s]." % (func.__name__, arg))
func()
print(" after %s called [%s]." % (func.__name__, arg))
return __deco
return _deco
def myfunc():
print(" myfunc() called.")
def myfunc1():
print(" myfunc() called.")
myfunc = deco()(myfunc)
myfunc1 = deco("haha1")(myfunc1)
这时再来看标准库functools中的wraps的使用,比如官网例子:
from functools import wraps
def my_decorator(f):
@wraps(f)
def wrapper(*args, **kwds):
print 'Calling decorated function'
return f(*args, **kwds)
return wrapper
@my_decorator
def example():
"""Docstring"""
print 'Called example function'
example()
print example.__name__
print example.__doc__
过程就是
def my_decorator(f):
def wrapper(*args, **kwds):
print 'Calling decorated function'
return f(*args, **kwds)
wrapper.__name__ = f.__name__
wrapper.__doc__ = f.__doc__
return wrapper
example = my_decorator(example)
这样就保留了原函数名称属性和doc,
标准库中函数wraps,可以这样理解:
def wraps(f):
def _f(*args,**kwargs):
f(*args,**kwargs)
_f.__name__ = f.__name
_f.__doc__ = f.__doc__
return _f
上面的wraps流程可以看出,如果直接使用wraps简直就是f = f(其实不能直接使用),所以一般都是如实例这样包藏在一个装饰器函数内部.
注:示例代码来自:Python装饰器学习(九步入门) 及 python标准库functools之wraps
来源:oschina
链接:https://my.oschina.net/u/1755923/blog/495293