Python中的多重装饰器
admin
2023-07-31 02:14:40
0

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

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

>>> test=first(test)
_second() was post to first()
>>> test

>>> 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

>>> test=first(True)(test)
__second() was post to _first()
>>> test

>>>

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

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

相关内容

热门资讯

Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
Apache Doris 2.... 亲爱的社区小伙伴们,我们很高兴地向大家宣布,Apache Doris 2.0.0 版本已于...
项目管理和工程管理的区别 项目管理 项目管理,顾名思义就是专注于开发和完成项目的管理,以实现目标并满足成功标准和项目要求。 工...