python 装饰器及标准库functools中的wraps

最近在看 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

相关文章
相关标签/搜索