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 数据清洗之数据合并、转换、过滤、排序
Feb 12 Python
Python中防止sql注入的方法详解
Feb 25 Python
Python读取文件内容的三种常用方式及效率比较
Oct 07 Python
pandas数据预处理之dataframe的groupby操作方法
Apr 13 Python
Python实现求解括号匹配问题的方法
Apr 17 Python
pandas 使用apply同时处理两列数据的方法
Apr 20 Python
对Python2与Python3中__bool__方法的差异详解
Nov 01 Python
Python使用paramiko操作linux的方法讲解
Feb 25 Python
python+openCV利用摄像头实现人员活动检测
Jun 22 Python
pytorch+lstm实现的pos示例
Jan 14 Python
常用python爬虫库介绍与简要说明
Jan 25 Python
Python+Selenium自动化环境搭建与操作基础详解
Mar 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
php 小乘法表实现代码
2009/07/16 PHP
php/js获取客户端mac地址的实现代码
2013/07/08 PHP
php实例分享之通过递归实现删除目录下的所有文件详解
2014/05/15 PHP
PHP SPL标准库之文件操作(SplFileInfo和SplFileObject)实例
2015/05/11 PHP
WordPress中重置文章循环的rewind_posts()函数讲解
2016/01/11 PHP
PHP中localeconv()函数的用法
2019/03/26 PHP
COM中获取JavaScript数组大小的代码
2009/11/22 Javascript
jQuery调用RESTful WCF示例代码(GET方法/POST方法)
2014/01/26 Javascript
js仿苹果iwatch外观的计时器代码分享
2015/08/26 Javascript
借助FileReader实现将文件编码为Base64后通过AJAX上传
2015/12/24 Javascript
浅谈AngularJS中ng-class的使用方法
2016/11/11 Javascript
纯js仿淘宝京东商品放大镜功能
2017/03/02 Javascript
详解Angular CLI + Electron 开发环境搭建
2017/07/20 Javascript
vue父组件向子组件传递多个数据的实例
2018/03/01 Javascript
javascript深拷贝、浅拷贝和循环引用深入理解
2018/05/27 Javascript
js指定日期增加指定月份的实现方法
2018/12/19 Javascript
vue实现图片预览组件封装与使用
2019/07/13 Javascript
JS图片懒加载的优点及实现原理
2020/01/10 Javascript
学前端,css与javascript重难点浅析
2020/06/11 Javascript
前端vue如何使用高德地图
2020/11/05 Javascript
浅谈python函数之作用域(python3.5)
2017/10/27 Python
用十张图详解TensorFlow数据读取机制(附代码)
2018/02/06 Python
python随机在一张图像上截取任意大小图片的方法
2019/01/24 Python
python SVD压缩图像的实现代码
2019/11/05 Python
基于Python+QT的gui程序开发实现
2020/07/03 Python
写出二分查找算法的两种实现
2013/05/13 面试题
最新的大学生找工作自我评价
2013/09/29 职场文书
公司离职证明范本
2014/01/13 职场文书
上课睡觉检讨书
2014/01/28 职场文书
2014年体检中心工作总结
2014/12/23 职场文书
二年级学生期末评语
2014/12/26 职场文书
市级三好学生评语
2014/12/29 职场文书
中英文求职信范文
2015/03/19 职场文书
会计求职信怎么写
2015/03/20 职场文书
2015年反腐倡廉工作总结
2015/05/14 职场文书
班级班风口号大全
2015/12/25 职场文书