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 19 Python
在unittest中使用 logging 模块记录测试数据的方法
Nov 30 Python
Python比较配置文件的方法实例详解
Jun 06 Python
在win64上使用bypy进行百度网盘文件上传功能
Jan 02 Python
Pytorch实现神经网络的分类方式
Jan 08 Python
浅谈matplotlib.pyplot与axes的关系
Mar 06 Python
Python常用编译器原理及特点解析
Mar 23 Python
jupyter lab文件导出/下载方式
Apr 22 Python
python不同版本的_new_不同点总结
Dec 09 Python
Python基础之操作MySQL数据库
May 06 Python
Python利用FlashText算法实现替换字符串
Mar 31 Python
python计算列表元素与乘积详情
Aug 05 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中使用Oracle数据库(2)
2006/10/09 PHP
用PHP控制用户的浏览器--ob*函数的使用说明
2007/03/16 PHP
PHP 面向对象实现代码
2009/11/11 PHP
用sql命令修改数据表中的一个字段为非空(not null)的语句
2010/06/04 PHP
将CMYK颜色值和RGB颜色相互转换的PHP代码
2014/07/28 PHP
php实现zip文件解压操作
2015/11/03 PHP
php+jQuery实现的三级导航栏下拉菜单显示效果
2017/08/10 PHP
laravel 去掉index.php伪静态的操作方法
2019/10/12 PHP
基于jQuery的日期选择控件
2009/10/27 Javascript
javascript作用域和闭包使用详解
2014/04/25 Javascript
JavaScript中判断整数的多种方法总结
2014/11/08 Javascript
完美实现bootstrap分页查询
2015/12/09 Javascript
详解Javascript中DOM的范围
2017/02/13 Javascript
详解react-webpack2-热模块替换[HMR]
2017/08/03 Javascript
Vue中跨域及打包部署到nginx跨域设置方法
2019/08/26 Javascript
python PyTorch预训练示例
2018/02/11 Python
详解Django中六个常用的自定义装饰器
2018/07/04 Python
详解numpy矩阵的创建与数据类型
2019/10/18 Python
Python如何重新加载模块
2020/07/29 Python
PyTorch中clone()、detach()及相关扩展详解
2020/12/09 Python
Html5移动端div固定到底部实现底部导航条的几种方式
2021/03/09 HTML / CSS
Hotter Shoes英国官网:英伦风格,舒适的鞋子
2017/12/28 全球购物
百度软件工程师职位
2013/02/14 面试题
潘婷洗发水广告词
2014/03/14 职场文书
秋天的怀念教学反思
2014/04/28 职场文书
秋天的图画教学反思
2014/05/01 职场文书
安全生产月宣传标语
2014/10/06 职场文书
党的群众路线教育实践活动个人整改措施落实情况
2014/11/04 职场文书
红旗渠导游词
2015/02/09 职场文书
4S店销售内勤岗位职责
2015/04/13 职场文书
金榜题名主持词
2015/07/02 职场文书
公司业务员管理制度
2015/08/05 职场文书
nginx基于域名,端口,不同IP的虚拟主机设置的实现
2021/03/31 Servers
MySQL如何构建数据表索引
2021/05/13 MySQL
pytorch交叉熵损失函数的weight参数的使用
2021/05/24 Python
MySQL中EXPLAIN语句及用法
2022/05/20 MySQL