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 ZipFile模块详解
Nov 01 Python
python实现博客文章爬虫示例
Feb 26 Python
Python网页解析利器BeautifulSoup安装使用介绍
Mar 17 Python
在Python的Django框架中编写错误提示页面
Jul 22 Python
在DigitalOcean的服务器上部署flaskblog应用
Dec 19 Python
Python的Flask框架中配置多个子域名的方法讲解
Jun 07 Python
Python进阶之递归函数的用法及其示例
Jan 31 Python
python os用法总结
Jun 08 Python
Python3 读、写Excel文件的操作方法
Oct 20 Python
python+selenium+PhantomJS抓取网页动态加载内容
Feb 25 Python
使用Python-OpenCV消除图像中孤立的小区域操作
Jul 05 Python
TensorFlow的自动求导原理分析
May 26 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中将网页导出为Word文档的代码
2012/05/25 PHP
jscript之List Excel Color Values
2007/06/13 Javascript
Prototype 学习 Prototype对象
2009/07/12 Javascript
基于Jquery与WebMethod投票功能实现代码
2011/01/19 Javascript
jQuery中.live()方法的用法深入解析
2013/12/30 Javascript
jQuery中的val()示例应用
2014/02/26 Javascript
JavaScript 开发工具webstrom使用指南
2014/12/09 Javascript
基于JavaScript实现移动端TAB触屏切换效果
2015/10/20 Javascript
JavaScript类型系统之布尔Boolean类型详解
2016/06/26 Javascript
JavaScript Ajax实现异步通信
2016/12/14 Javascript
vue 自定义提示框(Toast)组件的实现代码
2018/08/17 Javascript
如何为vuex实现带参数的 getter和state.commit
2019/01/04 Javascript
通过实例讲解JS如何防抖动
2019/06/15 Javascript
如何使用Javascript中的this关键字
2020/05/28 Javascript
Vue实现可移动水平时间轴
2020/06/29 Javascript
python实现k均值算法示例(k均值聚类算法)
2014/03/16 Python
python实现感知器
2017/12/19 Python
浅谈Python编程中3个常用的数据结构和算法
2019/04/30 Python
python 处理微信对账单数据的实例代码
2019/07/19 Python
python游戏开发的五个案例分享
2020/03/09 Python
Django查询优化及ajax编码格式原理解析
2020/03/25 Python
详解pandas.DataFrame.plot() 画图函数
2020/06/14 Python
Java爬虫技术框架之Heritrix框架详解
2020/07/22 Python
DJI大疆无人机官方商城:全球领先的无人飞行器研发和生产商
2016/12/21 全球购物
SmartBuyGlasses英国:购买太阳镜和眼镜
2018/01/29 全球购物
Laravel中Kafka的使用详解
2021/03/24 PHP
2014年母亲节寄语
2014/05/07 职场文书
党员承诺书怎么写
2014/05/20 职场文书
国贸专业毕业求职信
2014/06/11 职场文书
学校党的群众路线教育实践活动总结报告
2014/07/03 职场文书
特此通知格式
2015/04/27 职场文书
个人收入证明范本
2015/06/12 职场文书
2019年思想汇报
2019/06/20 职场文书
导游词之桂林
2019/08/20 职场文书
《我在为谁工作》:工作的质量往往决定生活的质量
2019/12/27 职场文书
修改MySQL的默认密码的四种小方法
2021/05/26 MySQL