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 __test10 return _test11 12 >>> @test(True)13 def say():return 'hello world'14 15 >>> say()16 Call the function say().17 hello world18 >>> @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 >>> @test31 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 __test10 return _test11 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 hello28 >>>
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=3211 12 13 >>> s=sy()14 Call sy.__init().15 >>> s16 <__main__.sy object at 0x0000000002C3E390>17 >>> s.value18 3219 >>>
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=value13 14 15 >>> s=sy('hello world')16 Call sy.__init().17 >>> s18 <__main__.sy object at 0x0000000003AF7748>19 >>> s.value20 '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 obj10 return __test11 return _test12 13 >>> @test()14 class sy(object):15 def __init__(self):16 self.value=3217 18 19 >>> s=sy()20 Call sy.__init().21 value = 3222 >>> @test(False)23 class sy(object):24 def __init__(self):25 self.value=3226 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 obj10 return __test11 return _test12 13 >>> @test()14 class sy(object):15 def __init__(self,value):16 self.value=value17 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=value26 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 function17 '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 function18 '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 function18 '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 function19 '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=3212 13 14 >>> s=sy()15 >>> s16 <__main__.sy object at 0x0000000003AAFA20>17 >>> s.value18 3219 >>>
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=value13 14 15 >>> s=sy('hello world')16 >>> s17 <__main__.sy object at 0x0000000003AAFA20>18 >>> s.value19 '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 obj10 return _call11 12 13 >>> @test(True)14 class sy(object):15 def __init__(self):16 self.value=3217 18 19 >>> s=sy()20 value = 3221 >>> s22 <__main__.sy object at 0x0000000003AB50B8>23 >>> s.value24 3225 >>>
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 obj10 return _call11 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=value18 19 20 >>> s=sy('hello world')21 value = 'hello world'22 >>> s23 <__main__.sy object at 0x0000000003AB5588>24 >>> s.value25 '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的定义中的用等号连接的只是有默认值的参数,它们并不一定会成为关键字参数,因为你仍然可以按照位置来传递它们。
新闻热点
疑难解答