装饰器本质上就是一个函数,这个函数接收其他函数作为参数,并将其以一个新的修改后的函数进行替换。
简单来说,装饰器的目的是为了实现代码的'封闭开放'.封闭,即表示已实现的功能代码块要封闭,需要随便改动。开放,是指基于原有功能模块的扩展开发。
本质上,装饰器会用一个动态创建的新函数来替换原来的函数。
如下是一个简单的装饰器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__ ' This is a original test function :param arg1: :return: ' >>> 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__ ' This is a original test function :param arg1: :return: ' >>> @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__ ' This is a original test function :param arg1: :return: ' >>>
此外,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'