functools.wraps: update_wrapper的封装

This is a convenience function for invoking partial(update_wrapper,wrapped=wrapped,assigned=assigned,updated=updated) as a function decorator when defining a wrapper function.

import functools

def log_cost_time(func):

    @functools.wraps(func)

    def wrapped(*args, **kwargs):

        import time

        begin = time.time()

        try:

            return func(*args, **kwargs)

        finally:

            print 'func %s cost %s' % (func.__name__, time.time() - begin)

    return wrapped

再查看complex_func.__name__ 输出就是 “complex_func”

装饰器也是可以带参数的。

def log_cost_time(stream):

    def inner_dec(func):

        def wrapped(*args, **kwargs):

            import time

            begin = time.time()

            try:

                return func(*args, **kwargs)

            finally:

                stream.write('func %s cost %s ' % (func.__name__, time.time() - begin))

        return wrapped

    return inner_dec

import sys

@log_cost_time(sys.stdout)

def complex_func(num):

    ret = 0

    for i in xrange(num):

        ret += i * i

    return ret

if __name__ == '__main__':

    print complex_func(100000)

code snippet 1

log_cost_time函数也接受一个参数,该参数用来指定信息的输出流,对于带参数的decorator

@dec(dec_args)

def func(*args, **kwargs):pass

等价于 func = dec(dec_args)(*args, **kwargs)。

装饰器对类的修饰也是很简单的,只不过平时用得不是很多。举个例子,我们需要给修改类的__str__方法,代码很简单。

def Haha(clz):

    clz.__str__ = lambda s: "Haha"

    return clz

class Widget(object):

    ''' class Widget '''

if __name__ == '__main__':

    w = Widget()

    print w

那什么场景下有必要使用decorator呢,设计模式中有一个模式也叫装饰器。我们先简单回顾一下设计模式中的装饰器模式,简单的一句话概述

动态地为某个对象增加额外的责任

  由于装饰器模式仅从外部改变组件,因此组件无需对它的装饰有任何了解;


回到Python中来,用decorator语法实现装饰器模式是很自然的,比如文中的示例代码,在不改变被装饰对象的同时增加了记录函数执行时间的额外功能。当然,由于Python语言的灵活性,decorator是可以修改被装饰的对象的(比如装饰类的例子)。decorator在python中用途非常广泛,下面列举几个方面:

(1)修改被装饰对象的属性或者行为

(2)处理被函数对象执行的上下文,比如设置环境变量,加log之类

(3)处理重复的逻辑,比如有N个函数都可能跑出异常,但是我们不关心这些异常,只要不向调用者传递异常就行了,这个时候可以写一个catchall的decorator,作用于所用可能跑出异常的函数

def catchall(func):

    @functools.wraps(func)

    def wrapped(*args, **kwargs):

        try:

            return func(*args, **kwargs)

        except:

            pass

    return wrapped

(4)框架代码,如flask, bottle等等,让使用者很方便就能使用框架,本质上也避免了重复代码。

你可能感兴趣的:(functools.wraps: update_wrapper的封装)