标签:
最近在看 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__, arg)) func() print(" after %s called [%s]." % (func.__name__, arg)) return __deco @d_deco#注意没有括号,第一处 def myfunc(): print(" myfunc() called.") @_deco#这也没括号,第二处 def myfunc1(): print(" myfunc1() called.") myfunc() myfunc1()
而参数arg在第一处,使用的是默认的"haha",第二处使用的是"haha1",
更直观的表达方式就是:
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
python 装饰器及标准库functools中的wraps
标签:
原文地址:http://my.oschina.net/chinesezhx/blog/495293