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的几条建议分享
Feb 10 Python
Python简单删除目录下文件以及文件夹的方法
May 27 Python
对python csv模块配置分隔符和引用符详解
Dec 12 Python
Python字符串的常见操作实例小结
Apr 08 Python
50行Python代码获取高考志愿信息的实现方法
Jul 23 Python
详解Python并发编程之从性能角度来初探并发编程
Aug 23 Python
适合Python初学者的一些编程技巧
Feb 12 Python
django xadmin中form_layout添加字段显示方式
Mar 30 Python
在python image 中实现安装中文字体
May 16 Python
手把手教你配置JupyterLab 环境的实现
Feb 02 Python
python编程实现清理微信重复缓存文件
Nov 01 Python
Python可视化神器pyecharts绘制水球图
Jul 07 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读取html并截取字符串的简单代码
2009/11/30 PHP
PHP session会话的安全性分析
2011/09/08 PHP
真正根据utf8编码的规律来进行截取字符串的函数(utf8版sub_str )
2012/10/24 PHP
php实现在多维数组中查找特定value的方法
2015/07/29 PHP
PHP strip_tags() 去字符串中的 HTML、XML 以及 PHP 标签的函数
2016/05/22 PHP
javascript URL锚点取值方法
2009/02/25 Javascript
JavaScript Event学习补遗 addEventSimple
2010/02/11 Javascript
js操作输入框中选择内容兼容IE及其他主流浏览器
2014/04/22 Javascript
js图片自动轮播代码分享(js图片轮播)
2014/05/06 Javascript
jQuery 获取/设置/删除DOM元素的属性以a元素为例
2014/05/23 Javascript
JS仿京东移动端手指拨动切换轮播图效果
2020/04/10 Javascript
Bootstrap基本模板的使用和理解1
2016/12/14 Javascript
微信小程序 Tab页切换更新数据
2017/01/05 Javascript
Bootstrap列表组学习使用
2017/02/09 Javascript
js 动态生成html 触发事件传参字符转义的实例
2017/02/14 Javascript
vue.js使用watch监听路由变化的方法
2018/07/08 Javascript
Vue-Quill-Editor富文本编辑器的使用教程
2018/09/21 Javascript
jQuery-App输入框实现实时搜索
2020/11/19 jQuery
python基础教程之udp端口扫描
2014/02/10 Python
python连接mysql并提交mysql事务示例
2014/03/05 Python
Python读写Excel文件方法介绍
2014/11/22 Python
浅谈Python 对象内存占用
2016/07/15 Python
Python设计模式之装饰模式实例详解
2019/01/21 Python
使用pyinstaller逆向.pyc文件
2019/12/20 Python
python GUI框架pyqt5 对图片进行流式布局的方法(瀑布流flowlayout)
2020/03/12 Python
利用PyTorch实现VGG16教程
2020/06/24 Python
如何利用Python 进行边缘检测
2020/10/14 Python
小型女装店的创业计划书
2014/01/09 职场文书
会议接待欢迎词
2014/01/12 职场文书
就业推荐表自我鉴定范文
2014/03/21 职场文书
2014年银行员工年终自我评价
2014/09/19 职场文书
学期个人工作总结
2015/02/13 职场文书
小学2016年第十八届推普周活动总结
2016/04/05 职场文书
2019让人心动的商业计划书
2019/06/27 职场文书
Python编程中内置的NotImplemented类型的用法
2022/03/23 Python
mysql查找连续出现n次以上的数字
2022/05/11 MySQL