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中使用__slots__方法的详细教程
Apr 28 Python
Python中encode()方法的使用简介
May 18 Python
Django中模版的子目录与include标签的使用方法
Jul 16 Python
由浅入深讲解python中的yield与generator
Apr 05 Python
Python判断变量是否为Json格式的字符串示例
May 03 Python
Sanic框架安装与简单入门示例
Jul 16 Python
Win8.1下安装Python3.6提示0x80240017错误的解决方法
Jul 31 Python
Python 忽略warning的输出方法
Oct 18 Python
浅谈python连续赋值可能引发的错误
Nov 10 Python
python 自动轨迹绘制的实例代码
Jul 05 Python
python进程的状态、创建及使用方法详解
Dec 06 Python
python的json包位置及用法总结
Jun 21 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/30 PHP
在Mac OS的PHP环境下安装配置MemCache的全过程解析
2016/02/15 PHP
PHP计算日期相差天数实例分析
2016/02/23 PHP
PHP基于rabbitmq操作类的生产者和消费者功能示例
2018/06/16 PHP
通过javascript设置css属性的代码
2009/12/28 Javascript
javascript实现的使用方向键控制光标在table单元格中切换
2010/11/17 Javascript
jQuery随机切换图片的小例子
2013/04/18 Javascript
Javascript 是你的高阶函数(高级应用)
2015/06/15 Javascript
基于jquery实现select选择框内容左右移动添加删除代码分享
2015/08/25 Javascript
jquery左右全屏大尺寸多图滑动效果代码分享
2015/08/28 Javascript
jquery+css实现动感的图片切换效果
2015/11/25 Javascript
详细探究ES6之Proxy代理
2016/07/22 Javascript
canvas实现绘制吃豆鱼效果
2017/01/12 Javascript
nodejs根据ip数组在百度地图中进行定位
2017/03/06 NodeJs
JavaScript 通过Ajax 动态加载CheckBox复选框
2017/08/31 Javascript
JavaScript的setter与getter方法
2017/11/29 Javascript
Angular4.0中引入laydate.js日期插件的方法教程
2017/12/25 Javascript
vue.js,ajax渲染页面的实例
2018/02/11 Javascript
Vue+penlayers实现多边形绘制及展示
2020/12/24 Vue.js
教你学会使用Python正则表达式
2017/09/07 Python
django文档学习之applications使用详解
2018/01/29 Python
在python中对变量判断是否为None的三种方法总结
2019/01/23 Python
Python 仅获取响应头, 不获取实体的实例
2019/08/21 Python
Django生成PDF文档显示网页上以及PDF中文显示乱码的解决方法
2019/12/17 Python
Python random模块制作简易的四位数验证码
2020/02/01 Python
浅谈keras中的batch_dot,dot方法和TensorFlow的matmul
2020/06/18 Python
Python执行时间的几种计算方法
2020/07/31 Python
Python+OpenCV图像处理——图像二值化的实现
2020/10/24 Python
Python 实现进度条的六种方式
2021/01/06 Python
波兰运动鞋网上商店:e-Sporting
2018/02/16 全球购物
亚洲最大的眼镜批发商和零售商之一:Glasseslit
2018/10/08 全球购物
药学专业毕业生求职信
2013/10/20 职场文书
党的群众路线对照检查材料
2014/08/27 职场文书
php字符串倒叙
2021/04/01 PHP
浅谈MySql update会锁定哪些范围的数据
2022/06/25 MySQL
基于Redission的分布式锁实战
2022/08/14 Redis