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 中if else 语句的作用及示例代码
Mar 05 Python
Python使用matplotlib模块绘制图像并设置标题与坐标轴等信息示例
May 04 Python
Python线程同步的实现代码
Oct 03 Python
python遍历文件夹找出文件夹后缀为py的文件方法
Oct 21 Python
Python实现钉钉发送报警消息的方法
Feb 20 Python
python 实现兔子生兔子示例
Nov 21 Python
Pycharm和Idea支持的vim插件的方法
Feb 21 Python
Pytorch 使用不同版本的cuda的方法步骤
Apr 02 Python
详解pyqt5的UI中嵌入matplotlib图形并实时刷新(挖坑和填坑)
Aug 07 Python
Anaconda使用IDLE的实现示例
Sep 23 Python
Python实现为PDF去除水印的示例代码
Apr 03 Python
python垃圾回收机制原理分析
Apr 13 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
无线电广播的开始
2002/01/30 无线电
PHP创建桌面快捷方式的实例代码
2014/02/17 PHP
php生成0~1随机小数的方法(必看)
2017/04/05 PHP
Laravel中unique和exists验证规则的优化详解
2018/01/28 PHP
php写app用的框架整理
2019/09/29 PHP
关于IFRAME 自适应高度的研究
2006/07/20 Javascript
基于jquery的图片的切换(以数字的形式)
2011/02/14 Javascript
javascript eval(func())使用示例
2013/12/05 Javascript
一个JavaScript防止表单重复提交的实例
2014/10/21 Javascript
jQuery幻灯片特效代码分享--鼠标滑过按钮时切换(2)
2020/11/18 Javascript
总结JavaScript三种数据存储方式之间的区别
2016/05/03 Javascript
js检测离开或刷新页面时表单数据是否更改的方法
2016/08/02 Javascript
BootStrap Validator对于隐藏域验证和程序赋值即时验证的问题浅析
2016/12/01 Javascript
读Javascript高性能编程重点笔记
2016/12/21 Javascript
Vue.js 60分钟快速入门教程
2017/03/28 Javascript
用原生JS实现简单的多选框功能
2017/06/12 Javascript
Angular中的ng-template及angular 使用ngTemplateOutlet 指令的方法
2018/08/08 Javascript
Django模板继承 extend标签实例代码详解
2019/05/16 Javascript
javascript二维数组和对象的深拷贝与浅拷贝实例分析
2019/10/26 Javascript
Node.JS获取GET,POST数据之queryString模块使用方法详解
2020/02/06 Javascript
跨平台python异步回调机制实现和使用方法
2013/11/26 Python
Python的Bottle框架的一些使用技巧介绍
2015/04/08 Python
python 默认参数问题的陷阱
2016/02/29 Python
浅谈Python类的__getitem__和__setitem__特殊方法
2016/12/25 Python
如何用Python破解wifi密码过程详解
2019/07/12 Python
python实现多进程按序号批量修改文件名的方法示例
2019/12/30 Python
Python模拟登入的N种方式(建议收藏)
2020/05/31 Python
Python web框架(django,flask)实现mysql数据库读写分离的示例
2020/11/18 Python
使用简单的CSS3属性实现炫酷读者墙效果
2014/01/08 HTML / CSS
澳大利亚UGG工厂直销:Australian Ugg Boots
2017/10/14 全球购物
护士的自我鉴定
2014/02/07 职场文书
物流业务员岗位职责
2014/02/08 职场文书
四年级科学教学反思
2014/02/10 职场文书
小学校长个人总结
2015/03/03 职场文书
党性教育心得体会(共6篇)
2016/01/21 职场文书
使用Pytorch训练two-head网络的操作
2021/05/28 Python