最近在看 flask的视图装饰器 时,突然想起预(复)习一下python的装饰器.html
这里有一篇比较好的讲解装饰器的书写的 Python装饰器学习(九步入门) .python
这里不单独记录装饰器的书写格式了,重点是工做流程.flask
首先常见的 装饰器 格式就是经过@语法糖,简便的写法,让流程有些不太清楚.app
装饰器不带参数的状况下:函数
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.
这个@语法糖的做用是:code
def myfunc(): print(" myfunc() called.") myfunc = deco(myfunc)
也就是如今的myfunc再也不是一开始定义的那个了,而变成了orm
def _deco(): print("before myfunc() called.") func() print(" after myfunc() called.")
这一点能够经过htm
print myfunc.__name__
而复杂一点的,装饰器带参数的,如:blog
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