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实现保存网页到本地示例
Mar 16 Python
Python新手在作用域方面经常容易碰到的问题
Apr 03 Python
最大K个数问题的Python版解法总结
Jun 16 Python
Python3安装Scrapy的方法步骤
Nov 23 Python
单利模式及python实现方式详解
Mar 20 Python
python 每天如何定时启动爬虫任务(实现方法分享)
May 21 Python
Python3.5基础之函数的定义与使用实例详解【参数、作用域、递归、重载等】
Apr 26 Python
pandas条件组合筛选和按范围筛选的示例代码
Aug 26 Python
调整Jupyter notebook的启动目录操作
Apr 10 Python
Python代码执行时间测量模块timeit用法解析
Jul 01 Python
python制作一个简单的gui 数据库查询界面
Nov 19 Python
在pycharm创建scrapy项目的实现步骤
Dec 01 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和ACCESS写聊天室(三)
2006/10/09 PHP
如何用PHP实现插入排序?
2013/04/10 PHP
Zend Framework动作助手Url用法详解
2016/03/05 PHP
使用ltrace工具跟踪PHP库函数调用的方法
2016/04/25 PHP
使用composer 安装 laravel框架的方法图文详解
2019/08/02 PHP
Laravel使用模型实现like模糊查询的例子
2019/10/24 PHP
基于jquery实现的可以编辑选择的下拉框的代码
2010/11/19 Javascript
xss文件页面内容读取(解决)
2010/11/28 Javascript
javascript的函数、创建对象、封装、属性和方法、继承
2011/03/10 Javascript
基于javascript 闭包基础分享
2013/07/10 Javascript
ECMAScript6的新特性箭头函数(Arrow Function)详细介绍
2014/06/07 Javascript
Express作者TJ告别Node.js奔向Go
2014/07/14 Javascript
Javascript使用post方法提交数据实例
2015/08/03 Javascript
JS实现网页右侧带动画效果的伸缩窗口代码
2015/10/29 Javascript
javascript汉字拼音互转的简单实例
2016/10/09 Javascript
D3.js封装文本实现自动换行和旋转平移等功能
2016/10/14 Javascript
.net MVC+Bootstrap下使用localResizeIMG上传图片
2017/04/21 Javascript
使用Math.max,Math.min获取数组中的最值实例
2017/04/25 Javascript
vue.js项目打包上线的图文教程
2017/11/16 Javascript
除Console.log()外更多的Javascript调试命令
2018/01/24 Javascript
使用JavaScript生成罗马字符的实例代码
2018/06/08 Javascript
谈谈IntersectionObserver懒加载的具体使用
2019/10/15 Javascript
Python实现抓取页面上链接的简单爬虫分享
2015/01/21 Python
Pandas标记删除重复记录的方法
2018/04/08 Python
python opencv实现图片旋转矩形分割
2018/07/26 Python
python用pandas数据加载、存储与文件格式的实例
2018/12/07 Python
Python selenium 自动化脚本打包成一个exe文件(推荐)
2020/01/14 Python
美国内衣品牌:Leonisa
2016/08/14 全球购物
必须要使用游标的SQL语句有那些
2012/05/07 面试题
经济与贸易专业应届生求职信
2013/11/19 职场文书
会计职业生涯规划书
2014/01/13 职场文书
竞选文艺委员演讲稿
2014/04/28 职场文书
学习演讲稿范文
2014/05/10 职场文书
企业总经理助理岗位职责
2014/09/12 职场文书
2015年教师节感恩寄语
2015/03/23 职场文书
朋友聚会开场白
2015/06/01 职场文书