首页 > 代码库 > 装饰器的原理及其用法

装饰器的原理及其用法

什么是装饰器
装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理, Web权限校验, Cache等。

装饰器的作用

很有名的例子,就是咖啡,加糖的咖啡,加牛奶的咖啡。 本质上,还是咖啡,只是在原有的东西上,做了“装饰”,使之附加一些功能或特性。例如记录日志,需要对某些函数进行记录,笨的办法,每个函数加入代码,如果代码变了,就悲催了,装饰器的办法,定义一个专门日志记录的装饰器,对需要的函数进行装饰,搞定。装饰器的作用就是为已经存在的对象添加额外的功能。

为什么装饰器要用这样的方式实现?


装饰器的种类根据三个‘对象’的不同搭配一般分为四种:

1.最完整的一种即是带参数的装饰器包装带参数的函数

def decorator_with_params_and_func_args(arg_of_decorator):
    def handle_func(func):
        def handle_args(*args, **kwargs):#如果这样设置参数形式的话,任何形式的func都可以放进来装饰。也就是说第十三行的函数可以是任意函数[搭配任意参数]。
            print "begin" #在此函数内可以对三个‘对象’[arg_of_decorator,func,*args, **kwargs]做任意处理(装饰)。
	    func(*args, **kwargs) 
	    print "end" 
	    print arg_of_decorator, func, args,kwargs
            return arg_of_decorator #一般有多少个def就有多少个return但是很明显此处不必要,因为在调用的时候[foo4(1, b=3)]一般不必要像返回什么东西,此处有返回所以最后会输出123.
	return handle_args #此处的return的一般是其下一层的函数名 
    return handle_func #此处的return的一般是其下一层的函数名

@decorator_with_params_and_func_args("123") 
def foo4(a, b=2): 
    print "Content" 

print foo4(1, b=3)
输出结果是:

begin
Content
end
123 <function foo4 at 0x204caa0> (1,) {‘b‘: 3}
123

由此我们可以得出一个装饰器的框架来:

def decorator(arg_of_decorator):
    def handle_func(func):
        def handle_args(*args, **kwargs):
            #对三个‘对象’的处理,可以添加一个return。
        return handle_args
    return handle_func


@decorator(arg_of_decorator)
def foo4(*args, **kwargs):
    #任意语句

foo4(*args, **kwargs)#如果上面handle_args函数有返回值的话此处则得到返回的结果。


既然整个框架都得出来了,那么我们可以看一下缺少一种参数的两种情形:不带参数的装饰器包装带参数的函数和带参数的装饰器包装不带参数的函数。


2.不带参数的装饰器包装带参数的函数

def decorator_with_func_args(func):#(arg_of_decorator):这儿可以直接是func做参数,因为少了

装饰器参数所以只有两层两层
    #def handle_func(func):
        def handle_args(*args, **kwargs):
            print "begin" 
	    func(*args, **kwargs) 
	    print "end" 
	    print  func, args,kwargs #arg_of_decorator,
            return 'here have no arg_of_decorator'#arg_of_decorator 
	return handle_args #此处返回的仍然是下一层函数的函数名
    #return handle_func

@decorator_with_func_args#("123")这儿不必要有括号和参数了 
def foo4(a, b=2): 
    print "Content" 

print foo4(1, b=3)
输出结果是:
begin
Content
end
<function foo4 at 0xfeba28> (1,) {‘b‘: 3}
here have no arg_of_decorator
3.带参数的装饰器包装不带参数的函数
def decorator_with_params(arg_of_decorator):
    def handle_func(func):
        #def handle_args(*args, **kwargs):
            print "begin" 
	    func()#(*args, **kwargs) 
	    print "end" 
	    print arg_of_decorator, func#, args,kwargs
            return func#arg_of_decorator 这儿需要返回函数,否则会出现错误:TypeError: 'NoneType' object is not callable
	#return handle_args 
    return handle_func 

@decorator_with_params("123") 
def foo4():#(a, b=2): 此处不再有参数
    print "Content" 

print foo4()#(1, b=3)
输出的结果为:
begin
Content
end
123 <function foo4 at 0x12a1aa0>
Content
None
这儿为什么需要返回func函数呢?我们看到前面两种情况不需要返回func函数。

4.还有最后一种情况即,不带参数的装饰器包装不带参数的函数

def decorator_with_no_params_and_no_func_args(func):#(arg_of_decorator):
    #def handle_func(func):
        #def handle_args(*args, **kwargs):
            print "begin" 
	    func()#(*args, **kwargs) 
	    print "end" 
	    print func#arg_of_decorator, func, args,kwargs
            return func#arg_of_decorator 
	#return handle_args 
    #return handle_func 

@decorator_with_no_params_and_no_func_args#("123") 
def foo4():#(a, b=2): 
    print "Content" 

print foo4()#(1, b=3)<strong>
</strong>
输出结果为:
begin
Content
end
<function foo4 at 0xb2ba28>
Content
None