Python多重装饰器

多重装饰器,即多个装饰器修饰同一个对象【实际上并非完全如此,且看下文详解】

1.装饰器无参数:

 1 >>> def first(func):
 2     print %s() was post to first()%func.func_name
 3     def _first(*args,**kw):
 4         print Call the function %s() in _first().%func.func_name
 5         return func(*args,**kw)
 6     return _first
 7 
 8 
 9 >>> def second(func):
10     print %s() was post to second()%func.func_name
11     def _second(*args,**kw):
12         print Call the function %s() in _second().%func.func_name
13         return func(*args,**kw)
14     return _second
15 
16 
17 >>> @first
18 @second
19 def test():return hello world
20 
21 test() was post to second()
22 _second() was post to first()
23 >>> test()
24 Call the function _second() in _first().
25 Call the function test() in _second().
26 hello world
27 >>> 

 

 实际上它是相当于下面的代码:

 1 >>> def test():
 2     return hello world
 3 
 4 >>> test=second(test)
 5 test() was post to second()
 6 >>> test
 7 <function _second at 0x000000000316D3C8>
 8 >>> test=first(test)
 9 _second() was post to first()
10 >>> test
11 <function _first at 0x000000000316D358>
12 >>> test()
13 Call the function _second() in _first().
14 Call the function test() in _second().
15 hello world
16 >>> 

 

 2.装饰器有参数:

 1 >>> def first(printResult=False):
 2     def _first(func):
 3         print %s() was post to _first()%func.func_name
 4         def __first(*args,**kw):
 5             print Call the function %s() in __first().% 6                   func.func_name
 7             if printResult:
 8                 print func(*args,**kw),#print in __first().
 9             else:
10                 return func(*args,**kw)
11         return __first
12     return _first
13 
14 >>> def second(printResult=False):
15     def _second(func):
16         print %s() was post to _second()%func.func_name
17         def __second(*args,**kw):
18             print Call the function %s() in __second().%19                   func.func_name
20             if printResult:
21                 print func(*args,**kw),#print in __second().
22             else:
23                 return func(*args,**kw)
24         return __second
25     return _second
26 
27 >>> @first(True)
28 @second(True)
29 def test():
30     return hello world
31 
32 test() was post to _second()
33 __second() was post to _first()
34 >>> test()
35 Call the function __second() in __first().
36 Call the function test() in __second().
37 hello world #print in __second().
38 None #print in __first().
39 >>> 

如上,第35行输出后调用__second(),而__second()中又调用了test()并print test(),而后返回__first()中继续执行print,而这个print语句print的内容是__second()返回的None

它等同于:

>>> def test():
    return hello world

>>> test=second(True)(test)
test() was post to _second()
>>> 
>>> test
<function __second at 0x000000000316D2E8>
>>> test=first(True)(test)
__second() was post to _first()
>>> test
<function __first at 0x0000000003344C18>
>>> 

3.多重装饰器的应用:

比如你是项目经理,你要求每一个代码块都必须有参数检查ArgsType和责任检查ResponsibilityRegister,这样就需要两个装饰器对此代码块进行监督。

#coding=utf-8
import os,sys,re
from collections import OrderedDict

def ArgsType(*argTypes,**kwTypes):
    u‘‘‘ArgsType(*argTypes,**kwTypes)
    options=[(‘opt_UseTypeOfDefaultValue‘,False)]

    以下为本函数相关的开关,并非类型检验相关的关键字参数,所有options:
    opt_UseTypeOfDefaultValue=>bool:False,为True时,将对没有指定类型的带默
                               认值的参数使用其默认值的类型
    ‘‘‘
    def _ArgsType(func):
        #确定所有的parameter name
        argNames=func.func_code.co_varnames[:func.func_code.co_argcount]
        #确定所有的default parameter
        defaults=func.func_defaults
        if defaults:
            defaults=dict(zip(argNames[-len(defaults):],defaults))
        else:defaults=None
        #将“参数类型关键字参数”中的所有“options关键字参数”提出
        options=dict()
        for option,default in [(opt_UseTypeOfDefaultValue,False)]:
            options[option]=kwTypes.pop(option,default)
        #argTypes和kwTypes的总长度应该与argNames一致
        if len(argTypes)+len(kwTypes)>len(argNames):
            raise Exception(Too much types to check %s().%func.func_name)
        #所有kwTypes中的键不能覆盖在argTypes中已经占用的names
        if not set(argNames[len(argTypes):]).issuperset(
            set(kwTypes.keys())):
            raise Exception(There is some key in kwTypes +
                which is not in argNames.)
        #确定所有的参数应该有的types
        types=OrderedDict()
        for name in argNames:types[name]=None
        if len(argTypes):
            for i in range(len(argTypes)):
                name=argNames[i]
                types[name]=argTypes[i]
        else:
            for name,t in kwTypes.items():
                types[name]=t
        if len(kwTypes):
            for name,t in kwTypes.items():
                types[name]=t
        #关于default parameter的type
        if options[opt_UseTypeOfDefaultValue]:
            for k,v in defaults.items():
                #如果default parameter的type没有另外指定,那么就使用
                #default parameter的default value的type
                if types[k]==None:
                    types[k]=type(v)
        def __ArgsType(*args,**kw):
            #order the args
            Args=OrderedDict()
            #init keys
            for name in argNames:Args[name]=None
            #init default values
            if defaults is not None:
                for k,v in defaults.items():
                    Args[k]=v
            #fill in all args
            for i in range(len(args)):
                Args[argNames[i]]=args[i]
            #fill in all keyword args
            for k,v in kw.items():
                Args[k]=v
            #check if there is some None in the values
            if defaults==None:
                for k in Args:
                    if Args[k]==None:
                        if defaults==None:
                            raise Exception((%s() needs %r parameter, +
                                which was not given)%(func.func_name,k))
                        else:
                           if not defaults.has_key(k):
                                raise Exception((Parameter %r of %s() is+
                                     not a default parameter)%                                    (k,func.func_name))
            #check all types
            for k in Args:
                if not isinstance(Args[k],types[k]):
                    raise TypeError((Parameter %r of %s() must be +
                        a %r object, but you post: %r)%                        (k,func.func_name,types[k],Args[k]))
            return func(*args,**kw)
        return __ArgsType
    return _ArgsType

def ResponsibilityRegister(author):
    def _ResponsibilityRegister(func):
        def __ResponsibilityRegister(*args,**kw):
            try:
                return func(*args,**kw)
            except Exception as e:
                print ("Something is wrong, It‘s %s‘s responsibility."%                       author).center(80,*)
                raise e
        return __ResponsibilityRegister
    return _ResponsibilityRegister

@ResponsibilityRegister(Kate)
@ArgsType(str,int)
def left(Str,Len=1):
    return Str[:Len]

print Good calling:
print left(hello world,8)
print Bad calling:
print left(3,7)

这里没有文档,所以调用者不知道,使用了错误的调用,导致出错,这是Kate的责任。

像上面这种,对代码有两种互不相干的检验时,就可以使用多重装饰器。

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。