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 相关文章推荐
python脚本实现统计日志文件中的ip访问次数代码分享
Aug 06 Python
Python中的异常处理简明介绍
Apr 13 Python
python3使用urllib模块制作网络爬虫
Apr 08 Python
Appium Python自动化测试之环境搭建的步骤
Jan 23 Python
阿里云ECS服务器部署django的方法
Aug 29 Python
Python数据可视化:顶级绘图库plotly详解
Dec 07 Python
使用pyqt5 tablewidget 单元格设置正则表达式
Dec 13 Python
python如何通过twisted搭建socket服务
Feb 03 Python
Python turtle库的画笔控制说明
Jun 28 Python
Python logging模块异步线程写日志实现过程解析
Jun 30 Python
Windows下PyCharm配置Anaconda环境(超详细教程)
Jul 31 Python
python中pivot()函数基础知识点
Jan 03 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
音乐朗读剧《MARS RED》2021年TV动画化决定!
2020/03/06 日漫
PHP中的超全局变量
2006/10/09 PHP
php下拉选项的批量操作的实现代码
2013/10/14 PHP
详谈PHP文件目录基础操作
2014/11/11 PHP
JavaScript 学习笔记(十二) dom
2010/01/21 Javascript
JavaScript fontcolor方法入门实例(按照指定的颜色来显示字符串)
2014/10/17 Javascript
30个经典的jQuery代码开发技巧
2014/12/15 Javascript
node.js中的fs.mkdir方法使用说明
2014/12/17 Javascript
jQuery中:file选择器用法实例
2015/01/04 Javascript
jquery实现可自动判断位置的弹出层效果代码
2015/10/12 Javascript
JS组件Bootstrap Table布局详解
2016/05/27 Javascript
AngularJS实现使用路由切换视图的方法
2017/01/24 Javascript
JS实现手写parseInt的方法示例
2017/09/24 Javascript
JS实现的哈夫曼编码示例【原始版与修改版】
2018/04/22 Javascript
vue配置多代理服务接口地址操作
2020/09/08 Javascript
vue使用element-ui实现表单验证
2020/12/13 Vue.js
为python设置socket代理的方法
2015/01/14 Python
Python实现多进程共享数据的方法分析
2017/12/04 Python
python批量读取txt文件为DataFrame的方法
2018/04/03 Python
python中将一个全部为int的list 转化为str的list方法
2018/04/09 Python
浅谈Python中重载isinstance继承关系的问题
2018/05/04 Python
matplotlib subplots 设置总图的标题方法
2018/05/25 Python
Python使用pyautogui模块实现自动化鼠标和键盘操作示例
2018/09/04 Python
pyqt5的QComboBox 使用模板的具体方法
2018/09/06 Python
python网络爬虫 CrawlSpider使用详解
2019/09/27 Python
Python网络编程之使用TCP方式传输文件操作示例
2019/11/01 Python
详解Python直接赋值,深拷贝和浅拷贝
2020/07/09 Python
HTML5录音实践总结(Preact)
2020/05/07 HTML / CSS
匈牙利超级网上商店和优惠:Alza.hu
2019/12/17 全球购物
2014入党积极分子批评与自我批评思想报告
2014/10/06 职场文书
2015年助残日活动总结
2015/03/27 职场文书
2015年前台个人工作总结
2015/04/03 职场文书
2015年科研工作总结范文
2015/05/13 职场文书
大学生自我鉴定怎么写
2019/05/07 职场文书
python 详解turtle画爱心代码
2022/02/15 Python
Vue如何清空对象
2022/03/03 Vue.js