Python装饰器,分两部分,一是装饰器本身的定义,一是被装饰器对象的定义。
一、函数式装饰器:装饰器本身是一个函数。
1.装饰函数:被装饰对象是一个函数
[1]装饰器无参数:
a.被装饰对象无参数:
1 >>> def test(func): 2 def _test(): 3 print 'Call the function %s().'%func.func_name 4 return func() 5 return _test 6 7 >>> @test 8 def say():return 'hello world' 9 10 >>> say() 11 Call the function say(). 12 'hello world' 13 >>>
b.被装饰对象有参数:
1 >>> def test(func): 2 def _test(*args,**kw): 3 print 'Call the function %s().'%func.func_name 4 return func(*args,**kw) 5 return _test 6 7 >>> @test 8 def left(Str,Len): 9 #The parameters of _test can be '(Str,Len)' in this case. 10 return Str[:Len] 11 12 >>> left('hello world',5) 13 Call the function left(). 14 'hello' 15 >>>
[2]装饰器有参数:
a.被装饰对象无参数:
1 >>> def test(printResult=False): 2 def _test(func): 3 def __test(): 4 print 'Call the function %s().'%func.func_name 5 if printResult: 6 print func() 7 else: 8 return func() 9 return __test 10 return _test 11 12 >>> @test(True) 13 def say():return 'hello world' 14 15 >>> say() 16 Call the function say(). 17 hello world 18 >>> @test(False) 19 def say():return 'hello world' 20 21 >>> say() 22 Call the function say(). 23 'hello world' 24 >>> @test() 25 def say():return 'hello world' 26 27 >>> say() 28 Call the function say(). 29 'hello world' 30 >>> @test 31 def say():return 'hello world' 32 33 >>> say() 34 35 Traceback (most recent call last): 36 File "<pyshell#224>", line 1, in <module> 37 say() 38 TypeError: _test() takes exactly 1 argument (0 given) 39 >>>
由上面这段代码中的最后两个例子可知:当装饰器有参数时,即使你启用装饰器的默认参数,不另外传递新值进去,也必须有一对括号,否则编译器会直接将func传递给test(),而不是传递给_test()
b.被装饰对象有参数:
1 >>> def test(printResult=False): 2 def _test(func): 3 def __test(*args,**kw): 4 print 'Call the function %s().'%func.func_name 5 if printResult: 6 print func(*args,**kw) 7 else: 8 return func(*args,**kw) 9 return __test 10 return _test 11 12 >>> @test() 13 def left(Str,Len): 14 #The parameters of __test can be '(Str,Len)' in this case. 15 return Str[:Len] 16 17 >>> left('hello world',5) 18 Call the function left(). 19 'hello' 20 >>> @test(True) 21 def left(Str,Len): 22 #The parameters of __test can be '(Str,Len)' in this case. 23 return Str[:Len] 24 25 >>> left('hello world',5) 26 Call the function left(). 27 hello 28 >>>
2.装饰类:被装饰的对象是一个类
[1]装饰器无参数:
a.被装饰对象无参数:
1 >>> def test(cls): 2 def _test(): 3 clsName=re.findall('(w+)',repr(cls))[-1] 4 print 'Call %s.__init().'%clsName 5 return cls() 6 return _test 7 8 >>> @test 9 class sy(object): 10 value=32 11 12 13 >>> s=sy() 14 Call sy.__init(). 15 >>> s 16 <__main__.sy object at 0x0000000002C3E390> 17 >>> s.value 18 32 19 >>>
b.被装饰对象有参数:
1 >>> def test(cls): 2 def _test(*args,**kw): 3 clsName=re.findall('(w+)',repr(cls))[-1] 4 print 'Call %s.__init().'%clsName 5 return cls(*args,**kw) 6 return _test 7 8 >>> @test 9 class sy(object): 10 def __init__(self,value): 11 #The parameters of _test can be '(value)' in this case. 12 self.value=value 13 14 15 >>> s=sy('hello world') 16 Call sy.__init(). 17 >>> s 18 <__main__.sy object at 0x0000000003AF7748> 19 >>> s.value 20 'hello world' 21 >>>
[2]装饰器有参数:
a.被装饰对象无参数:
1 >>> def test(printValue=True): 2 def _test(cls): 3 def __test(): 4 clsName=re.findall('(w+)',repr(cls))[-1] 5 print 'Call %s.__init().'%clsName 6 obj=cls() 7 if printValue: 8 print 'value = %r'%obj.value 9 return obj 10 return __test 11 return _test 12 13 >>> @test() 14 class sy(object): 15 def __init__(self): 16 self.value=32 17 18 19 >>> s=sy() 20 Call sy.__init(). 21 value = 32 22 >>> @test(False) 23 class sy(object): 24 def __init__(self): 25 self.value=32 26 27 28 >>> s=sy() 29 Call sy.__init(). 30 >>>
b.被装饰对象有参数:
1 >>> def test(printValue=True): 2 def _test(cls): 3 def __test(*args,**kw): 4 clsName=re.findall('(w+)',repr(cls))[-1] 5 print 'Call %s.__init().'%clsName 6 obj=cls(*args,**kw) 7 if printValue: 8 print 'value = %r'%obj.value 9 return obj 10 return __test 11 return _test 12 13 >>> @test() 14 class sy(object): 15 def __init__(self,value): 16 self.value=value 17 18 19 >>> s=sy('hello world') 20 Call sy.__init(). 21 value = 'hello world' 22 >>> @test(False) 23 class sy(object): 24 def __init__(self,value): 25 self.value=value 26 27 28 >>> s=sy('hello world') 29 Call sy.__init(). 30 >>>
二、类式装饰器:装饰器本身是一个类,借用__init__()和__call__()来实现职能
1.装饰函数:被装饰对象是一个函数
[1]装饰器无参数:
a.被装饰对象无参数:
1 >>> class test(object): 2 def __init__(self,func): 3 self._func=func 4 def __call__(self): 5 return self._func() 6 7 8 >>> @test 9 def say(): 10 return 'hello world' 11 12 >>> say() 13 'hello world' 14 >>>
b.被装饰对象有参数:
1 >>> class test(object): 2 def __init__(self,func): 3 self._func=func 4 def __call__(self,*args,**kw): 5 return self._func(*args,**kw) 6 7 8 >>> @test 9 def left(Str,Len): 10 #The parameters of __call__ can be '(self,Str,Len)' in this case. 11 return Str[:Len] 12 13 >>> left('hello world',5) 14 'hello' 15 >>>
[2]装饰器有参数
a.被装饰对象无参数:
1 >>> class test(object): 2 def __init__(self,beforeinfo='Call function'): 3 self.beforeInfo=beforeinfo 4 def __call__(self,func): 5 def _call(): 6 print self.beforeInfo 7 return func() 8 return _call 9 10 11 >>> @test() 12 def say(): 13 return 'hello world' 14 15 >>> say() 16 Call function 17 'hello world' 18 >>>
或者:
1 >>> class test(object): 2 def __init__(self,beforeinfo='Call function'): 3 self.beforeInfo=beforeinfo 4 def __call__(self,func): 5 self._func=func 6 return self._call 7 def _call(self): 8 print self.beforeInfo 9 return self._func() 10 11 12 >>> @test() 13 def say(): 14 return 'hello world' 15 16 >>> say() 17 Call function 18 'hello world' 19 >>>
b.被装饰对象有参数:
1 >>> class test(object): 2 def __init__(self,beforeinfo='Call function'): 3 self.beforeInfo=beforeinfo 4 def __call__(self,func): 5 def _call(*args,**kw): 6 print self.beforeInfo 7 return func(*args,**kw) 8 return _call 9 10 11 >>> @test() 12 def left(Str,Len): 13 #The parameters of _call can be '(Str,Len)' in this case. 14 return Str[:Len] 15 16 >>> left('hello world',5) 17 Call function 18 'hello' 19 >>>
或者:
1 >>> class test(object): 2 def __init__(self,beforeinfo='Call function'): 3 self.beforeInfo=beforeinfo 4 def __call__(self,func): 5 self._func=func 6 return self._call 7 def _call(self,*args,**kw): 8 print self.beforeInfo 9 return self._func(*args,**kw) 10 11 12 >>> @test() 13 def left(Str,Len): 14 #The parameters of _call can be '(self,Str,Len)' in this case. 15 return Str[:Len] 16 17 >>> left('hello world',5) 18 Call function 19 'hello' 20 >>>
2.装饰类:被装饰对象是一个类
[1]装饰器无参数:
a.被装饰对象无参数:
1 >>> class test(object): 2 def __init__(self,cls): 3 self._cls=cls 4 def __call__(self): 5 return self._cls() 6 7 8 >>> @test 9 class sy(object): 10 def __init__(self): 11 self.value=32 12 13 14 >>> s=sy() 15 >>> s 16 <__main__.sy object at 0x0000000003AAFA20> 17 >>> s.value 18 32 19 >>>
b.被装饰对象有参数:
1 >>> class test(object): 2 def __init__(self,cls): 3 self._cls=cls 4 def __call__(self,*args,**kw): 5 return self._cls(*args,**kw) 6 7 8 >>> @test 9 class sy(object): 10 def __init__(self,value): 11 #The parameters of __call__ can be '(self,value)' in this case. 12 self.value=value 13 14 15 >>> s=sy('hello world') 16 >>> s 17 <__main__.sy object at 0x0000000003AAFA20> 18 >>> s.value 19 'hello world' 20 >>>
[2]装饰器有参数:
a.被装饰对象无参数:
1 >>> class test(object): 2 def __init__(self,printValue=False): 3 self._printValue=printValue 4 def __call__(self,cls): 5 def _call(): 6 obj=cls() 7 if self._printValue: 8 print 'value = %r'%obj.value 9 return obj 10 return _call 11 12 13 >>> @test(True) 14 class sy(object): 15 def __init__(self): 16 self.value=32 17 18 19 >>> s=sy() 20 value = 32 21 >>> s 22 <__main__.sy object at 0x0000000003AB50B8> 23 >>> s.value 24 32 25 >>>
b.被装饰对象有参数:
1 >>> class test(object): 2 def __init__(self,printValue=False): 3 self._printValue=printValue 4 def __call__(self,cls): 5 def _call(*args,**kw): 6 obj=cls(*args,**kw) 7 if self._printValue: 8 print 'value = %r'%obj.value 9 return obj 10 return _call 11 12 13 >>> @test(True) 14 class sy(object): 15 def __init__(self,value): 16 #The parameters of _call can be '(value)' in this case. 17 self.value=value 18 19 20 >>> s=sy('hello world') 21 value = 'hello world' 22 >>> s 23 <__main__.sy object at 0x0000000003AB5588> 24 >>> s.value 25 'hello world' 26 >>>
总结:【1】@decorator后面不带括号时(也即装饰器无参数时),效果就相当于先定义func或cls,而后执行赋值操作func=decorator(func)或cls=decorator(cls);
【2】@decorator后面带括号时(也即装饰器有参数时),效果就相当于先定义func或cls,而后执行赋值操作 func=decorator(decoratorArgs)(func)或cls=decorator(decoratorArgs)(cls);
【3】如上将func或cls重新赋值后,此时的func或cls也不再是原来定义时的func或cls,而是一个可执行体,你只需要传入参数就可调用,func(args)=>返回值或者输出,cls(args)=>object of cls;
【4】最后通过赋值返回的执行体是多样的,可以是闭包,也可以是外部函数;当被装饰的是一个类时,还可以是类内部方法,函数;
【5】另外要想真正了解装饰器,一定要了解func.func_code.co_varnames,func.func_defaults,func.func_argcount,通过它们你可以以func的定义之外,还原func的参数列表,详见Python多重装饰器中的最后一个例子中的ArgsType;另外关键字参数是因为调用而出现的,而不是因为func的定义,func的定义中的用等号连接的只是有默认值的参数,它们并不一定会成为关键字参数,因为你仍然可以按照位置来传递它们。