3Days

Python Decorator分析

decorator本身是一个函数,这个函数的功能是接受被修饰的函数(decorated)作为参数,返回包装函数(wrapper)替换被修饰函数(decorated)。

@decorator
func

等同于 func = decorator(func)。大部分情况下wrapper函数必须要和decorated函数具有相同的参数,这样在wrapper函数中可以执行decorated函数,并增加一些拓展流程。基于此decorator的原则如下:

  • 对于自定义decorator,wrapper函数的参数要参考目标函数设计。
  • 如果使用系统decorator,因为wrapper函数是明确的,所以目标函数的设计要参考wrapper函数的参数。

decorator接受目标函数为参数,并返回wrapper函数,因此不能接受额外的参数。为了传送额外的参数给decorator函数,可以创建decorator maker函数接受参数并返回decorator函数,然后使用decorator完成函数替换,将目标函数替换为wrapper函数。

示例:

def mydecorator_maker(*args, **kwargs):
    print 'this is decorator maker function... with args %s, kwargs %s' % (args, kwargs)
    def mydecorator(func):
        print 'this is decorator... with args %s, kwargs %s' % (args, kwargs)
        def decorator_wrapper(func_arg1, func_arg2):
            print 'this is decorator wrapper, before function... with arg1 %s, arg2 %s' % (func_arg1, func_arg2)
            func(func_arg1, func_arg2)
            print "this is decorator wrapper, after function"
        return decorator_wrapper
    return mydecorator

@mydecorator_maker(1, 2, 3, test='test')
def mydecorated_function(func_arg1, func_arg2):
    print 'this is decorated function with arg1 %s, arg2 %s' % (func_arg1, func_arg2)

mydecorated_function('lily', 'Baby')

output:

this is decorator maker function... with args (1, 2, 3), kwargs {'test': 'test'}

this is decorator... with args (1, 2, 3), kwargs {'test': 'test'}

this is decorator wrapper, before function... with arg1 lily, arg2 Baby

this is decorated function with arg1 lily, arg2 Baby

this is decorator wrapper, after function

this is decorator maker function...

这种通过一个maker函数来接受额外的参数,并且做一些额外参数的处理的实现方式非常简明。拓展一下,因为decorator的函数替换的特点,可以对decorator函数进行一次decorator来实现额外参数的处理。首先梳理一下实现逻辑:

  • decorator的原理是将被decorated函数替换为wrapper函数。wrapper函数获取decorated函数的参数,执行decorated函数并在之前之后进行业务拓展处理。
  • decorated decorator函数根据上述原理,和普通的decorator没有不同。只是在decorator上加一个decorator使其增加处理额外参数的能力。
  • decoratordecorator将原decorator函数变为一个接受参数的wrapper函数,在这个函数执行后将decorator返回。继续之前的decorator流程。
  • decoratordecorator函数中的wrapper函数与普通的wrapper函数最大的不同在于不执行decorator函数,而是返回decorator函数。因此不需要保持参数的一直,带来额外参数的支持。

    这种参数的变换不一致和上述wrapper参数保持一致的原则有悖,但是依然符合decorator进行函数替换的基本功能设计。

示例:

def decorator_decorator(decorator_to_decorated):
    print 'This decorator decorator will decorate decorator passed in...'
    print 'passed in decorator is %s ' % decorator_to_decorated
    def decorator_wrapper(*args, **kwargs):
        print 'decorator wrapper do something with args %s, kwargs %s...' % (args, kwargs)
        return decorator_to_decorated
    return decorator_wrapper

@decorator_decorator
def decorated_decorator(func):
    print 'func  %s is decorated here' % func
    def wrapper(func_arg1, func_arg2):
        print 'wrapper with arg1 %s, args2 %s' % (func_arg1, func_arg2)
        return func(func_arg1, func_arg2)
    return wrapper

@decorated_decorator(1, 2, 3, test='test')
def decorated_function(func_arg1, func_arg2):
    print 'decorated function with func arg1 %s, arg2 %s' % (func_arg1, func_arg2)
    print 'do something in decorated function'

decorated_function('Liliy', 'Baby')

output:

This decorator decorator will decorate decorator passed in...

passed in decorator is <function decorateddecorator at 0x111a99c80>

decorator wrapper do something with args (1, 2, 3), kwargs {'test': 'test'}...

func <function decorated
function at 0x111b2bc08> is decorated here

wrapper with arg1 Liliy, args2 Baby

decorated function with func arg1 Liliy, arg2 Baby

do something in decorated function

posted on 2016-03-21 17:26  3Days  阅读(162)  评论(0编辑  收藏  举报

导航