• 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的责任。

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

  • 相关阅读:
    k8s是什么
    jmeter性能测试的策略
    面试的灵魂拷问:你最大的缺点是什么?
    面试的灵魂拷问:你做过的最令你自豪的事情是什么?
    面试的灵魂拷问:你犯过的最大的失误是什么?
    5-django rest framework,搭建api,这是最重要的章节
    4-restfulapi的介绍,vue代码结构
    组合恒等式证明——「Zeilberger 老爷子的 T 恤上写了啥?」
    「NOI2020」 美食家 【矩阵快速幂】
    [CEOI2014] The Wall【最短路】
  • 原文地址:https://www.cnblogs.com/nutix/p/4415577.html
Copyright © 2020-2023  润新知