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的Urllib库的一些高级用法
Apr 30 Python
Python中title()方法的使用简介
May 20 Python
Python微信公众号开发平台
Jan 25 Python
python抓取网页中链接的静态图片
Jan 29 Python
浅谈pandas中DataFrame关于显示值省略的解决方法
Apr 08 Python
Django中更改默认数据库为mysql的方法示例
Dec 05 Python
python实现二维插值的三维显示
Dec 17 Python
python opencv对图像进行旋转且不裁剪图片的实现方法
Jul 09 Python
如何不用安装python就能在.NET里调用Python库
Jul 12 Python
python实现单目标、多目标、多尺度、自定义特征的KCF跟踪算法(实例代码)
Jan 08 Python
Python通过2种方法输出带颜色字体
Mar 02 Python
pytorch中的model=model.to(device)使用说明
May 24 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 生成N个不重复的随机数
2015/01/21 PHP
Yii框架中用response保存cookie,用request读取cookie的原理解析
2019/09/04 PHP
JS 动态加载脚本的4种方法
2009/05/05 Javascript
推荐40个非常优秀的jQuery插件和教程【系列三】
2011/11/09 Javascript
Extjs中TabPane如何嵌套在其他网页中实现思路及代码
2013/01/27 Javascript
js实现浏览器的各种菜单命令比如打印、查看源文件等等
2013/10/24 Javascript
浅析js预加载/延迟加载
2014/09/25 Javascript
javascript密码强度校验代码(两种方法)
2015/08/10 Javascript
详解 javascript中offsetleft属性的用法
2015/11/11 Javascript
jQuery实现在HTML文档加载完毕后自动执行某个事件的方法
2017/05/08 jQuery
Vue上传组件vue Simple Uploader的用法示例
2017/08/25 Javascript
移动web开发之touch事件实例详解
2018/01/17 Javascript
vue实现裁切图片同时实现放大、缩小、旋转功能
2018/03/02 Javascript
Vue实现一个无限加载列表功能
2018/11/13 Javascript
详解Vue源码之数据的代理访问
2018/12/11 Javascript
Vue源码之关于vm.$delete()/Vue.use()内部原理详解
2019/05/01 Javascript
使用apifm-wxapi模块中的问题及解决方法
2019/08/05 Javascript
JavaScript和TypeScript中的void的具体使用
2019/09/12 Javascript
element中的$confirm的使用
2020/04/26 Javascript
python根据给定文件返回文件名和扩展名的方法
2015/03/27 Python
Python实现Sqlite将字段当做索引进行查询的方法
2016/07/21 Python
python list转矩阵的实例讲解
2018/08/04 Python
Python使用Flask-SQLAlchemy连接数据库操作示例
2018/08/31 Python
win10环境下配置vscode python开发环境的教程详解
2019/10/16 Python
tensorflow 获取所有variable或tensor的name示例
2020/01/04 Python
python实现简单井字棋游戏
2020/03/04 Python
Python xlrd模块导入过程及常用操作
2020/06/10 Python
解析HTML5中的新功能本地存储localStorage
2016/03/01 HTML / CSS
linux面试相关问题
2012/08/11 面试题
thinkphp5 redis缓存新增方法实例讲解
2021/03/24 PHP
建设办主任四风问题整改思路和措施
2014/09/20 职场文书
新学期开学标语2015
2015/07/16 职场文书
部门主管竞聘书
2015/09/15 职场文书
《所见》教学反思
2016/02/23 职场文书
js之ajax文件上传
2021/05/13 Javascript
node快速搭建后台的实现步骤
2022/02/18 NodeJs