码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2015-08-21 00:32:45      阅读:238      评论:0      收藏:0      [点我收藏+]

标签:

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!