Python装饰器

装饰器本质上就是一个函数,这个函数接收其他函数作为参数,并将其以一个新的修改后的函数进行替换。

简单来说,装饰器的目的是为了实现代码的'封闭开放'.封闭,即表示已实现的功能代码块要封闭,需要随便改动。开放,是指基于原有功能模块的扩展开发。

本质上,装饰器会用一个动态创建的新函数来替换原来的函数。

 

如下是一个简单的装饰器template:

 1 def extra_func(f):
 2     def wrapper(*args,**kwargs):
 3         ...
 4         extra code here
 5         ...
 6         return f(*args,**kwargs)
 7     return wrapper
 8 
 9 @extra_func
10 def original_func(*args,**kwargs)
11     ...
12     action here
13     ...
14     return 

上面的装饰器创建的新函数会缺少一些原函数的属性,比如:

>>> def test(arg1='k1'):
    '''
    This is a original test function
    :param arg1:
    :return:
    '''
    print(arg1)
  
>>> test()
k1
>>> test.__name__
'test'
>>> test.__doc__
'\n    This is a original test function\n    :param arg1:\n    :return:\n    '
>>> def extra_func(f):
    def wrapper(*args,**kwargs):
        print("this is decorator")
        return f(*args,**kwargs)
    return wrapper

>>> @extra_func
def test(arg1='k1'):
    '''
    This is a original test function
    :param arg1:
    :return:
    '''
    print(arg1)

>>> test()
this is decorator
k1    
>>> test.__name__
'wrapper'
>>> test.__doc__
>>> 

为了让新函数能够有原函数的属性,可以视同functools模块复制属性,如下:

 

>>> import functools
>>> def extra_func(f):
    @functools.wraps(f)
    def wrapper(*args,**kwargs):
        print("this is updated decorator")
        return f(*args,**kwargs)
    return wrapper

>>> def test(arg1='k1'):
    '''
    This is a original test function
    :param arg1:
    :return:
    '''
    print(arg1)

    
>>> test()
k1
>>> test.__name__
'test'
>>> test.__doc__
'\n    This is a original test function\n    :param arg1:\n    :return:\n    '
>>> @extra_func
def test(arg1='k1'):
    '''
    This is a original test function
    :param arg1:
    :return:
    '''
    print(arg1)

    
>>> test()
this is updated decorator
k1
>>> test.__name__
'test'
>>> test.__doc__
'\n    This is a original test function\n    :param arg1:\n    :return:\n    '
>>> 

此外,inspect模块能够用来获取被装饰函数的参数,使得装饰器变得更加方便,比如:

>>> import functools
>>> import inspect
>>> def extra_func(f):
    @functools.wraps(f)
    def wrapper(*args,**kwargs):
        print("this is decorator")
        func_args = inspect.getcallargs(f,*args,**kwargs)
        if func_args.get('arg1')!='k1':
            raise Exception("required arg1 missing!")
        return f(*args,**kwargs)
    return wrapper

>>> def test(arg1='k1',arg2='k2'):
    '''
    This is a original test function
    :param arg1:
    :return:
    '''
    print(arg1)

    
>>> test(arg1='k1')
k1
>>> test(arg1='k2')
k2
>>> @extra_func
def test(arg1='k1',arg2='k2'):
    '''
    This is a original test function
    :param arg1:
    :return:
    '''
    print(arg1)

    
>>> test(arg1='k1')
this is decorator
k1
>>> test(arg1='k2')
this is decorator
Traceback (most recent call last):
  File "<pyshell#17>", line 1, in <module>
    test(arg1='k2')
  File "<pyshell#8>", line 7, in wrapper
    raise Exception("required arg1 missing!")
Exception: required arg1 missing!
>>> 

另外装饰器也可以变的很复杂,如下(例子转自http://www.cnblogs.com/wupeiqi/articles/4980620.html):

def Before(request,kargs):
    print 'before'
      
def After(request,kargs):
    print 'after'
  
  
def Filter(before_func,after_func):
    def outer(main_func):
        def wrapper(request,kargs):
              
            before_result = before_func(request,kargs)
            if(before_result != None):
                return before_result;
              
            main_result = main_func(request,kargs)
            if(main_result != None):
                return main_result;
              
            after_result = after_func(request,kargs)
            if(after_result != None):
                return after_result;
              
        return wrapper
    return outer
      
@Filter(Before, After)
def Index(request,kargs):
    print 'index'

 

posted @ 2016-10-24 17:03  LCdre  阅读(214)  评论(0编辑  收藏  举报