当前位置 博文首页 > Python中的多重装饰器

    Python中的多重装饰器

    作者:admin 时间:2021-07-31 18:48

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

    1.装饰器无参数:

    复制代码 代码如下:

    >>> def first(func):
        print '%s() was post to first()'%func.func_name
        def _first(*args,**kw):
            print 'Call the function %s() in _first().'%func.func_name
            return func(*args,**kw)
        return _first


    >>> def second(func):
        print '%s() was post to second()'%func.func_name
        def _second(*args,**kw):
            print 'Call the function %s() in _second().'%func.func_name
            return func(*args,**kw)
        return _second


    >>> @first
    @second
    def test():return 'hello world'

    test() was post to second()
    _second() was post to first()
    >>> test()
    Call the function _second() in _first().
    Call the function test() in _second().
    'hello world'
    >>>

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

    复制代码 代码如下:

    >>> def test():
        return 'hello world'

    >>> test=second(test)
    test() was post to second()
    >>> test
    <function _second at 0x000000000316D3C8>
    >>> test=first(test)
    _second() was post to first()
    >>> test
    <function _first at 0x000000000316D358>
    >>> test()
    Call the function _second() in _first().
    Call the function test() in _second().
    'hello world'
    >>>


    2.装饰器有参数:
    复制代码 代码如下:

    >>> def first(printResult=False):
        def _first(func):
            print '%s() was post to _first()'%func.func_name
            def __first(*args,**kw):
                print 'Call the function %s() in __first().'%\
                      func.func_name
                if printResult:
                    print func(*args,**kw),'#print in __first().'
                else:
                    return func(*args,**kw)
            return __first
        return _first

    >>> def second(printResult=False):
        def _second(func):
            print '%s() was post to _second()'%func.func_name
            def __second(*args,**kw):
                print 'Call the function %s() in __second().'%\
                      func.func_name
                if printResult:
                    print func(*args,**kw),'#print in __second().'
                else:
                    return func(*args,**kw)
            return __second
        return _second

    >>> @first(True)
    @second(True)
    def test():
        return 'hello world'

    test() was post to _second()
    __second() was post to _first()
    >>> test()
    Call the function __second() in __first().
    Call the function test() in __second().
    hello world #print in __second().
    None #print in __first().
    >>>

    如上,第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的责任。

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

    jsjbwy
    下一篇:没有了