Python装饰器,分两部分,一是装饰器本身的定义,一是被装饰器对象的定义。
一、函数式装饰器:装饰器本身是一个函数。
1.装饰函数:被装饰对象是一个函数
[1]装饰器无参数:
a.被装饰对象无参数:
1>>>deftest(func):2def_test():3PRint'Call the function %s().'%func.func_name4returnfunc()5return_test67>>>@test8defsay():return'hello world'910>>>say()11Call the function say().12'hello world'13>>>
b.被装饰对象有参数:
1>>>deftest(func):2def_test(*args,**kw):3print'Call the function %s().'%func.func_name4returnfunc(*args,**kw)5return_test67>>>@test8defleft(Str,Len):9#The parameters of _test can be '(Str,Len)' in this case.10returnStr[:Len]1112>>> left('hello world',5)13Call the function left().14'hello'15>>>
[2]装饰器有参数:
a.被装饰对象无参数:
1>>>deftest(printResult=False):2def_test(func):3def__test():4print'Call the function %s().'%func.func_name5ifprintResult:6printfunc()7else:8returnfunc()9return__test10return_test1112>>>@test(True)13defsay():return'hello world'1415>>>say()16Call the function say().17hello world18>>>@test(False)19defsay():return'hello world'2021>>>say()22Call the function say().23'hello world'24>>>@test()25defsay():return'hello world'2627>>>say()28Call the function say().29'hello world'30>>>@test31defsay():return'hello world'3233>>>say()3435Traceback (most recent call last):36File"<pyshell#224>", line 1,in<module>37say()38TypeError: _test() takes exactly 1argument (0 given)39>>>
由上面这段代码中的最后两个例子可知:当装饰器有参数时,即使你启用装饰器的默认参数,不另外传递新值进去,也必须有一对括号,否则编译器会直接将func传递给test(),而不是传递给_test()
b.被装饰对象有参数:
1>>>deftest(printResult=False):2def_test(func):3def__test(*args,**kw):4print'Call the function %s().'%func.func_name5ifprintResult:6printfunc(*args,**kw)7else:8returnfunc(*args,**kw)9return__test10return_test1112>>>@test()13defleft(Str,Len):14#The parameters of __test can be '(Str,Len)' in this case.15returnStr[:Len]1617>>> left('hello world',5)18Call the function left().19'hello'20>>>@test(True)21defleft(Str,Len):22#The parameters of __test can be '(Str,Len)' in this case.23returnStr[:Len]2425>>> left('hello world',5)26Call the function left().27hello28>>>
2.装饰类:被装饰的对象是一个类
[1]装饰器无参数:
a.被装饰对象无参数:
1>>>deftest(cls):2def_test():3clsName=re.findall('(\w+)',repr(cls))[-1]4print'Call %s.__init().'%clsName5returncls()6return_test78>>>@test9classsy(object):10value=32111213>>> s=sy()14Call sy.__init().15>>>s16<__main__.sy object at 0x0000000002C3E390>17>>>s.value183219>>>
b.被装饰对象有参数:
1>>>deftest(cls):2def_test(*args,**kw):3clsName=re.findall('(\w+)',repr(cls))[-1]4print'Call %s.__init().'%clsName5returncls(*args,**kw)6return_test78>>>@test9classsy(object):10def__init__(self,value):11#The parameters of _test can be '(value)' in this case.12self.value=value131415>>> s=sy('hello world')16Call sy.__init().17>>>s18<__main__.sy object at 0x0000000003AF7748>19>>>s.value20'hello world'21>>>
[2]装饰器有参数:
a.被装饰对象无参数:
1>>>deftest(printValue=True):2def_test(cls):3def__test():4clsName=re.findall('(\w+)',repr(cls))[-1]5print'Call %s.__init().'%clsName6obj=cls()7ifprintValue:8print'value = %r'%obj.value9returnobj10return__test11return_test1213>>>@test()14classsy(object):15def__init__(self):16self.value=32171819>>> s=sy()20Call sy.__init().21value = 3222>>>@test(False)23classsy(object):24def__init__(self):25self.value=32262728>>> s=sy()29Call sy.__init().30>>>
b.被装饰对象有参数:
1>>>deftest(printValue=True):2def_test(cls):3def__test(*args,**kw):4clsName=re.findall('(\w+)',repr(cls))[-1]5print'Call %s.__init().'%clsName6obj=cls(*args,**kw)7ifprintValue:8print'value = %r'%obj.value9returnobj10return__test11return_test1213>>>@test()14classsy(object):15def__init__(self,value):16self.value=value171819>>> s=sy('hello world')20Call sy.__init().21value ='hello world'22>>>@test(False)23classsy(object):24def__init__(self,value):25self.value=value262728>>> s=sy('hello world')29Call sy.__init().30>>>
二、类式装饰器:装饰器本身是一个类,借用__init__()和__call__()来实现职能
1.装饰函数:被装饰对象是一个函数
[1]装饰器无参数:
a.被装饰对象无参数:
1>>>classtest(object):2def__init__(self,func):3self._func=func4def__call__(self):5returnself._func()678>>>@test9defsay():10return'hello world'1112>>>say()13'hello world'14>>>
b.被装饰对象有参数:
1>>>classtest(object):2def__init__(self,func):3self._func=func4def__call__(self,*args,**kw):5returnself._func(*args,**kw)678>>>@test9defleft(Str,Len):10#The parameters of __call__ can be '(self,Str,Len)' in this case.11returnStr[:Len]1213>>> left('hello world',5)14'hello'15>>>
[2]装饰器有参数
a.被装饰对象无参数:
1>>>classtest(object):2def__init__(self,beforeinfo='Call function'):3self.beforeInfo=beforeinfo4def__call__(self,func):5def_call():6printself.beforeInfo7returnfunc()8return_call91011>>>@test()12defsay():13return'hello world'1415>>>say()16Call function17'hello world'18>>>
或者:
1>>>classtest(object):2def__init__(self,beforeinfo='Call function'):3self.beforeInfo=beforeinfo4def__call__(self,func):5self._func=func6returnself._call7def_call(self):8printself.beforeInfo9returnself._func()101112>>>@test()13defsay():14return'hello world'1516>>>say()17Call function18'hello world'19>>>
b.被装饰对象有参数:
1>>>classtest(object):2def__init__(self,beforeinfo='Call function'):3self.beforeInfo=beforeinfo4def__call__(self,func):5def_call(*args,**kw):6printself.beforeInfo7returnfunc(*args,**kw)8return_call91011>>>@test()12defleft(Str,Len):13#The parameters of _call can be '(Str,Len)' in this case.14returnStr[:Len]1516>>> left('hello world',5)17Call function18'hello'19>>>
或者:
1>>>classtest(object):2def__init__(self,beforeinfo='Call function'):3self.beforeInfo=beforeinfo4def__call__(self,func):5self._func=func6returnself._call7def_call(self,*args,**kw):8printself.beforeInfo9returnself._func(*args,**kw)101112>>>@test()13defleft(Str,Len):14#The parameters of _call can be '(self,Str,Len)' in this case.15returnStr[:Len]1617>>> left('hello world',5)18Call function19'hello'20>>>
2.装饰类:被装饰对象是一个类
[1]装饰器无参数:
a.被装饰对象无参数:
1>>>classtest(object):2def__init__(self,cls):3self._cls=cls4def__call__(self):5returnself._cls()678>>>@test9classsy(object):10def__init__(self):11self.value=32121314>>> s=sy()15>>>s16<__main__.sy object at 0x0000000003AAFA20>17>>>s.value183219>>>
b.被装饰对象有参数:
1>>>classtest(object):2def__init__(self,cls):3self._cls=cls4def__call__(self,*args,**kw):5returnself._cls(*args,**kw)678>>>@test9classsy(object):10def__init__(self,value):11#The parameters of __call__ can be '(self,value)' in this case.12self.value=value131415>>> s=sy('hello world')16>>>s17<__main__.sy object at 0x0000000003AAFA20>18>>>s.value19'hello world'20>>>
[2]装饰器有参数:
a.被装饰对象无参数:
1>>>classtest(object):2def__init__(self,printValue=False):3self._printValue=printValue4def__call__(self,cls):5def_call():6obj=cls()7ifself._printValue:8print'value = %r'%obj.value9returnobj10return_call111213>>>@test(True)14classsy(object):15def__init__(self):16self.value=32171819>>> s=sy()20value = 3221>>>s22<__main__.sy object at 0x0000000003AB50B8>23>>>s.value243225>>>
b.被装饰对象有参数:
1>>>classtest(object):2def__init__(self,printValue=False):3self._printValue=printValue4def__call__(self,cls):5def_call(*args,**kw):6obj=cls(*args,**kw)7ifself._printValue:8print'value = %r'%obj.value9returnobj10return_call111213>>>@test(True)14classsy(object):15def__init__(self,value):16#The parameters of _call can be '(value)' in this case.17self.value=value181920>>> s=sy('hello world')21value ='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的定义中的用等号连接的只是有默认值的参数,它们并不一定会成为关键字参数,因为你仍然可以按照位置来传递它们。