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 相关文章推荐
pygame播放音乐的方法
May 19 Python
python实现ping的方法
Jul 06 Python
python 爬虫一键爬取 淘宝天猫宝贝页面主图颜色图和详情图的教程
May 22 Python
python中join()方法介绍
Oct 11 Python
Python3的介绍、安装和命令行的认识(推荐)
Oct 20 Python
Linux下Pycharm、Anaconda环境配置及使用踩坑
Dec 19 Python
Python之时间和日期使用小结
Feb 14 Python
Python 限定函数参数的类型及默认值方式
Dec 24 Python
Tensorflow的常用矩阵生成方式
Jan 04 Python
Python猴子补丁知识点总结
Jan 05 Python
python如何变换环境
Jul 21 Python
Python OpenCV中的numpy与图像类型转换操作
Dec 11 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
自动跳转中英文页面
2006/10/09 PHP
轻松修复Discuz!数据库
2008/05/03 PHP
PHP开发中常用的三个表单验证函数使用小结
2010/03/03 PHP
使用Discuz关键词服务器实现PHP中文分词
2014/03/11 PHP
php简单实现屏蔽指定ip段用户的访问
2015/04/29 PHP
thinkPHP实现基于ajax的评论回复功能
2018/06/22 PHP
PHP fprintf()函数用法讲解
2019/02/16 PHP
Javascript 面向对象(三)接口代码
2012/05/23 Javascript
JavaScript通过事件代理高亮显示表格行的方法
2015/05/27 Javascript
jquery div模态窗口的简单实例
2016/05/28 Javascript
深入理解JavaScript中的call、apply、bind方法的区别
2016/05/30 Javascript
关于JavaScript数组你所不知道的3件事
2016/08/24 Javascript
js监听键盘事件的方法_原生和jquery的区别详解
2016/10/10 Javascript
jQuery实现动态删除LI的方法
2017/05/30 jQuery
深入解析nodejs HTTP服务
2017/07/25 NodeJs
JS实现的简单标签点击切换功能示例
2017/09/21 Javascript
浅谈Vue网络请求之interceptors实际应用
2018/02/28 Javascript
让你5分钟掌握9个JavaScript小技巧
2018/06/09 Javascript
vue 详情跳转至列表页实现列表页缓存
2019/03/27 Javascript
深入理解es6块级作用域的使用
2019/03/28 Javascript
微信小程序实现图片翻转效果的实例代码
2019/09/20 Javascript
JavaScript进制转换实现方法解析
2020/01/18 Javascript
npm全局环境变量配置详解
2020/12/15 Javascript
Python键盘输入转换为列表的实例
2018/06/23 Python
python 字典修改键(key)的几种方法
2018/08/10 Python
python 实现图片上传接口开发 并生成可以访问的图片url
2019/12/18 Python
详解python破解zip文件密码的方法
2020/01/13 Python
python hmac模块验证客户端的合法性
2020/11/07 Python
html5的localstorage详解
2017/05/09 HTML / CSS
美国受信赖的教育产品供应商:Nest Learning
2018/06/14 全球购物
教学评估实施方案
2014/03/16 职场文书
令人印象深刻的自荐信
2014/05/25 职场文书
2014审计局领导班子民主生活会对照检查材料思想汇报
2014/09/20 职场文书
三八红旗手主要事迹材料
2015/11/04 职场文书
Python如何利用正则表达式爬取网页信息及图片
2021/04/17 Python
MATLAB 全景图切割及盒图显示的实现步骤
2021/05/14 Python