Python中的多重装饰器


Posted in Python onApril 11, 2015

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

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

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

Python 相关文章推荐
C#返回当前系统所有可用驱动器符号的方法
Apr 18 Python
进一步探究Python中的正则表达式
Apr 28 Python
在CentOS6上安装Python2.7的解决方法
Jan 09 Python
Python图像处理之识别图像中的文字(实例讲解)
May 10 Python
关于python写入文件自动换行的问题
Jun 23 Python
python抓取京东小米8手机配置信息
Nov 13 Python
pygame实现贪吃蛇游戏(下)
Oct 29 Python
python实现12306登录并保存cookie的方法示例
Dec 17 Python
python爬取天气数据的实例详解
Nov 20 Python
Python爬虫后获取重定向url的两种方法
Jan 19 Python
python实现MySQL指定表增量同步数据到clickhouse的脚本
Feb 26 Python
Python实现文本文件拆分写入到多个文本文件的方法
Apr 18 Python
Python中的各种装饰器详解
Apr 11 #Python
将Django使用的数据库从MySQL迁移到PostgreSQL的教程
Apr 11 #Python
Python返回真假值(True or False)小技巧
Apr 10 #Python
Python选择排序、冒泡排序、合并排序代码实例
Apr 10 #Python
Python字符串中查找子串小技巧
Apr 10 #Python
简单介绍Ruby中的CGI编程
Apr 10 #Python
详细介绍Ruby中的正则表达式
Apr 10 #Python
You might like
php操作mysqli(示例代码)
2013/10/28 PHP
PHP版QQ互联OAuth示例代码分享
2015/07/05 PHP
PHP使用finfo_file()函数检测上传图片类型的实现方法
2017/04/18 PHP
PHP调用API接口实现天气查询功能的示例
2017/09/21 PHP
php和C#的yield迭代器实现方法对比分析
2019/07/17 PHP
PHP数组实际占用内存大小原理解析
2020/12/11 PHP
Prototype使用指南之hash.js
2007/01/10 Javascript
用javascript做拖动布局的思路
2008/05/31 Javascript
jquery 常用操作整理 基础入门篇
2009/10/14 Javascript
判断JS对象是否拥有某种属性的两种方式
2013/12/02 Javascript
js使下拉列表框可编辑不止是选择
2013/12/12 Javascript
JavaScript中的对象序列化介绍
2014/12/30 Javascript
jquery实现滑屏大图定时收缩为小banner图片的广告代码
2015/09/02 Javascript
javascript中的previousSibling和nextSibling的正确用法
2015/09/16 Javascript
JS字符串的切分用法实例
2016/02/22 Javascript
Javascript使用SWFUpload进行多文件上传
2016/11/16 Javascript
canvas实现弧形可拖动进度条效果
2017/05/11 Javascript
详解微信小程序 template添加绑定事件
2017/06/23 Javascript
JS简单实现点击跳转登陆邮箱功能的方法
2017/10/31 Javascript
微信小程序实现的日期午别医生排班表功能示例
2019/01/09 Javascript
vue移动端使用canvas签名的实现
2020/01/15 Javascript
解决vue+webpack项目接口跨域出现的问题
2020/08/10 Javascript
python实现写数字文件名的递增保存文件方法
2018/10/25 Python
使用python opencv对目录下图片进行去重的方法
2019/01/12 Python
在PyTorch中Tensor的查找和筛选例子
2019/08/18 Python
中邮全球便购:中国邮政速递物流
2017/03/04 全球购物
DNA测试:Orig3n
2019/03/01 全球购物
工商管理实习生自我鉴定范文
2013/12/18 职场文书
实用求职信范文分享
2013/12/25 职场文书
初中地理教学反思
2014/01/11 职场文书
2014年度党员自我评议
2014/09/13 职场文书
营运督导岗位职责
2015/04/10 职场文书
新学期开学标语2015
2015/07/16 职场文书
2019年入党思想汇报格式与要求
2019/06/25 职场文书
研究生毕业登记表的自我鉴定范文
2019/07/15 职场文书
PHP新手指南
2021/04/01 PHP