Python中的各种装饰器详解


Posted in Python onApril 11, 2015

Python装饰器,分两部分,一是装饰器本身的定义,一是被装饰器对象的定义。

一、函数式装饰器:装饰器本身是一个函数。

1.装饰函数:被装饰对象是一个函数

[1]装饰器无参数:

a.被装饰对象无参数:

>>> def test(func):

    def _test():

        print 'Call the function %s().'%func.func_name

        return func()

    return _test
>>> @test

def say():return 'hello world'
>>> say()

Call the function say().

'hello world'

>>>

b.被装饰对象有参数:

>>> def test(func):

    def _test(*args,**kw):

        print 'Call the function %s().'%func.func_name

        return func(*args,**kw)

    return _test
>>> @test

def left(Str,Len):

    #The parameters of _test can be '(Str,Len)' in this case.

    return Str[:Len]
>>> left('hello world',5)

Call the function left().

'hello'

>>>

[2]装饰器有参数:

a.被装饰对象无参数:

>>> def test(printResult=False):

    def _test(func):

        def __test():

            print 'Call the function %s().'%func.func_name

            if printResult:

                print func()

            else:

                return func()

        return __test

    return _test
>>> @test(True)

def say():return 'hello world'
>>> say()

Call the function say().

hello world

>>> @test(False)

def say():return 'hello world'
>>> say()

Call the function say().

'hello world'

>>> @test()

def say():return 'hello world'
>>> say()

Call the function say().

'hello world'

>>> @test

def say():return 'hello world'
>>> say()
Traceback (most recent call last):

  File "<pyshell#224>", line 1, in <module>

    say()

TypeError: _test() takes exactly 1 argument (0 given)

>>>

由上面这段代码中的最后两个例子可知:当装饰器有参数时,即使你启用装饰器的默认参数,不另外传递新值进去,也必须有一对括号,否则编译器会直接将func传递给test(),而不是传递给_test()

b.被装饰对象有参数:

>>> def test(printResult=False):

    def _test(func):

        def __test(*args,**kw):

            print 'Call the function %s().'%func.func_name

            if printResult:

                print func(*args,**kw)

            else:

                return func(*args,**kw)

        return __test

    return _test
>>> @test()

def left(Str,Len):

    #The parameters of __test can be '(Str,Len)' in this case.

    return Str[:Len]
>>> left('hello world',5)

Call the function left().

'hello'

>>> @test(True)

def left(Str,Len):

    #The parameters of __test can be '(Str,Len)' in this case.

    return Str[:Len]
>>> left('hello world',5)

Call the function left().

hello

>>>

 
2.装饰类:被装饰的对象是一个类

[1]装饰器无参数:

a.被装饰对象无参数:

>>> def test(cls):

    def _test():

        clsName=re.findall('(\w+)',repr(cls))[-1]

        print 'Call %s.__init().'%clsName

        return cls()

    return _test
>>> @test

class sy(object):

    value=32
    

>>> s=sy()

Call sy.__init().

>>> s

<__main__.sy object at 0x0000000002C3E390>

>>> s.value

32

>>>

b.被装饰对象有参数:
>>> def test(cls):

    def _test(*args,**kw):

        clsName=re.findall('(\w+)',repr(cls))[-1]

        print 'Call %s.__init().'%clsName

        return cls(*args,**kw)

    return _test
>>> @test

class sy(object):

    def __init__(self,value):

                #The parameters of _test can be '(value)' in this case.

        self.value=value
        

>>> s=sy('hello world')

Call sy.__init().

>>> s

<__main__.sy object at 0x0000000003AF7748>

>>> s.value

'hello world'

>>>

 [2]装饰器有参数:

a.被装饰对象无参数:

>>> def test(printValue=True):

    def _test(cls):

        def __test():

            clsName=re.findall('(\w+)',repr(cls))[-1]

            print 'Call %s.__init().'%clsName

            obj=cls()

            if printValue:

                print 'value = %r'%obj.value

            return obj

        return __test

    return _test
>>> @test()

class sy(object):

    def __init__(self):

        self.value=32
        

>>> s=sy()

Call sy.__init().

value = 32

>>> @test(False)

class sy(object):

    def __init__(self):

        self.value=32
        

>>> s=sy()

Call sy.__init().

>>>

 b.被装饰对象有参数:
 

 >>> def test(printValue=True):

    def _test(cls):

        def __test(*args,**kw):

            clsName=re.findall('(\w+)',repr(cls))[-1]

            print 'Call %s.__init().'%clsName

            obj=cls(*args,**kw)

            if printValue:

                print 'value = %r'%obj.value

            return obj

        return __test

    return _test
>>> @test()

class sy(object):

    def __init__(self,value):

        self.value=value
        

>>> s=sy('hello world')

Call sy.__init().

value = 'hello world'

>>> @test(False)

class sy(object):

    def __init__(self,value):

        self.value=value
        

>>> s=sy('hello world')

Call sy.__init().

>>>

 

 二、类式装饰器:装饰器本身是一个类,借用__init__()和__call__()来实现职能

1.装饰函数:被装饰对象是一个函数

[1]装饰器无参数:

a.被装饰对象无参数:

>>> class test(object):

    def __init__(self,func):

        self._func=func

    def __call__(self):

        return self._func()
    

>>> @test

def say():

    return 'hello world'
>>> say()

'hello world'

>>>

b.被装饰对象有参数:

>>> class test(object):

    def __init__(self,func):

        self._func=func

    def __call__(self,*args,**kw):

        return self._func(*args,**kw)
    

>>> @test

def left(Str,Len):

    #The parameters of __call__ can be '(self,Str,Len)' in this case.

    return Str[:Len]
>>> left('hello world',5)

'hello'

>>>

 [2]装饰器有参数

a.被装饰对象无参数:

>>> class test(object):

    def __init__(self,beforeinfo='Call function'):

        self.beforeInfo=beforeinfo

    def __call__(self,func):

        def _call():

            print self.beforeInfo

            return func()

        return _call
    

>>> @test()

def say():

    return 'hello world'
>>> say()

Call function

'hello world'

>>>

或者:

 >>> class test(object):

    def __init__(self,beforeinfo='Call function'):

        self.beforeInfo=beforeinfo

    def __call__(self,func):

        self._func=func

        return self._call

    def _call(self):

        print self.beforeInfo

        return self._func()
    

>>> @test()

def say():

    return 'hello world'
>>> say()

Call function

'hello world'

>>>

 b.被装饰对象有参数:
 

 >>> class test(object):

    def __init__(self,beforeinfo='Call function'):

        self.beforeInfo=beforeinfo

    def __call__(self,func):

        def _call(*args,**kw):

            print self.beforeInfo

            return func(*args,**kw)

        return _call
    

>>> @test()

def left(Str,Len):

    #The parameters of _call can be '(Str,Len)' in this case.

    return Str[:Len]
>>> left('hello world',5)

Call function

'hello'

>>>

 

 或者:
 

 >>> class test(object):

    def __init__(self,beforeinfo='Call function'):

        self.beforeInfo=beforeinfo

    def __call__(self,func):

        self._func=func

        return self._call

    def _call(self,*args,**kw):

        print self.beforeInfo

        return self._func(*args,**kw)
    

>>> @test()

def left(Str,Len):

    #The parameters of _call can be '(self,Str,Len)' in this case.

    return Str[:Len]
>>> left('hello world',5)

Call function

'hello'

>>>

 

  2.装饰类:被装饰对象是一个类

[1]装饰器无参数:

a.被装饰对象无参数:

>>> class test(object):

    def __init__(self,cls):

        self._cls=cls

    def __call__(self):

        return self._cls()
    

>>> @test

class sy(object):

    def __init__(self):

        self.value=32
    

>>> s=sy()

>>> s

<__main__.sy object at 0x0000000003AAFA20>

>>> s.value

32

>>>

 b.被装饰对象有参数:
 

 >>> class test(object):

    def __init__(self,cls):

        self._cls=cls

    def __call__(self,*args,**kw):

        return self._cls(*args,**kw)
    

>>> @test

class sy(object):

    def __init__(self,value):

        #The parameters of __call__ can be '(self,value)' in this case.

        self.value=value
        

>>> s=sy('hello world')

>>> s

<__main__.sy object at 0x0000000003AAFA20>

>>> s.value

'hello world'

>>>

 

 [2]装饰器有参数:

a.被装饰对象无参数:

>>> class test(object):

    def __init__(self,printValue=False):

        self._printValue=printValue

    def __call__(self,cls):

        def _call():

            obj=cls()

            if self._printValue:

                print 'value = %r'%obj.value

            return obj

        return _call
    

>>> @test(True)

class sy(object):

    def __init__(self):

        self.value=32
        

>>> s=sy()

value = 32

>>> s

<__main__.sy object at 0x0000000003AB50B8>

>>> s.value

32

>>>

 b.被装饰对象有参数:
 

 >>> class test(object):

    def __init__(self,printValue=False):

        self._printValue=printValue

    def __call__(self,cls):

        def _call(*args,**kw):

            obj=cls(*args,**kw)

            if self._printValue:

                print 'value = %r'%obj.value

            return obj

        return _call
    

>>> @test(True)

class sy(object):

    def __init__(self,value):

        #The parameters of _call can be '(value)' in this case.

        self.value=value
        

>>> s=sy('hello world')

value = 'hello world'

>>> s

<__main__.sy object at 0x0000000003AB5588>

>>> s.value

'hello world'

>>>

 

 总结:【1】@decorator后面不带括号时(也即装饰器无参数时),效果就相当于先定义func或cls,而后执行赋值操作func=decorator(func)或cls=decorator(cls);

【2】@decorator后面带括号时(也即装饰器有参数时),效果就相当于先定义func或cls,而后执行赋值操作 func=decorator(decoratorArgs)(func)或cls=decorator(decoratorArgs)(cls);

【3】如上将func或cls重新赋值后,此时的func或cls也不再是原来定义时的func或cls,而是一个可执行体,你只需要传入参数就可调用,func(args)=>返回值或者输出,cls(args)=>object of cls;

【4】最后通过赋值返回的执行体是多样的,可以是闭包,也可以是外部函数;当被装饰的是一个类时,还可以是类内部方法,函数;

【5】另外要想真正了解装饰器,一定要了解func.func_code.co_varnames,func.func_defaults,通过它们你可以以func的定义之外,还原func的参数列表;另外关键字参数是因为调用而出现的,而不是因为func的定义,func的定义中的用等号连接的只是有默认值的参数,它们并不一定会成为关键字参数,因为你仍然可以按照位置来传递它们。

Python 相关文章推荐
Python程序中用csv模块来操作csv文件的基本使用教程
Mar 03 Python
Python的Twisted框架中使用Deferred对象来管理回调函数
May 25 Python
解决python3 网络请求路径包含中文的问题
May 10 Python
python pygame实现2048游戏
Nov 20 Python
关于python下cv.waitKey无响应的原因及解决方法
Jan 10 Python
python3利用ctypes传入一个字符串类型的列表方法
Feb 12 Python
python 实现识别图片上的数字
Jul 30 Python
twilio python自动拨打电话,播放自定义mp3音频的方法
Aug 08 Python
pandas read_excel()和to_excel()函数解析
Sep 19 Python
tensorflow 获取checkpoint中的变量列表实例
Feb 11 Python
Python 将 QQ 好友头像生成祝福语的实现代码
May 03 Python
Python 高效编程技巧分享
Sep 10 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
对于Python的Django框架部署的一些建议
Apr 09 #Python
You might like
PHP中json_encode、json_decode与serialize、unserialize的性能测试分析
2010/06/09 PHP
PHP 文本文章分页代码 按标记或长度(不涉及数据库)
2012/06/07 PHP
关于WordPress的SEO优化相关的一些PHP页面脚本技巧
2015/12/10 PHP
Yii视图CGridView实现操作按钮定义地址示例
2016/07/14 PHP
JavaScript实现拼音排序的方法
2012/11/20 Javascript
jQuery之自动完成组件的深入解析
2013/06/19 Javascript
javascript常用的正则表达式实例
2014/05/15 Javascript
ES6新特性五:Set与Map的数据结构实例分析
2017/04/21 Javascript
微信小程序实现瀑布流布局与无限加载的方法详解
2017/05/12 Javascript
vue 文件目录结构详解
2017/11/24 Javascript
微信小程序slider组件使用详解
2018/01/31 Javascript
vue代理和跨域问题的解决
2018/07/18 Javascript
jquery.pager.js分页实现详解
2019/07/29 jQuery
js瀑布流布局的实现
2020/06/28 Javascript
JS实现简易贪吃蛇游戏
2020/08/24 Javascript
Nuxt 嵌套路由nuxt-child组件用法(父子页面组件的传值)
2020/11/05 Javascript
[01:09:24]Ti4开幕式
2014/07/19 DOTA
[59:08]DOTA2上海特级锦标赛C组小组赛#2 LGD VS Newbee第一局
2016/02/27 DOTA
[02:22]2018DOTA2亚洲邀请赛VG赛前采访
2018/04/03 DOTA
分享python数据统计的一些小技巧
2016/07/21 Python
django manage.py扩展自定义命令方法
2018/05/27 Python
可能是最全面的 Python 字符串拼接总结【收藏】
2018/07/09 Python
图文详解python安装Scrapy框架步骤
2019/05/20 Python
python实现爬虫抓取小说功能示例【抓取金庸小说】
2019/08/09 Python
如何基于python操作excel并获取内容
2019/12/24 Python
flask框架渲染Jinja模板与传入模板变量操作详解
2020/01/25 Python
如何使用selenium和requests组合实现登录页面
2020/02/03 Python
Python unittest单元测试框架实现参数化
2020/04/29 Python
VSCode配合pipenv搞定虚拟环境的实现方法
2020/05/17 Python
波兰最大的度假胜地和城市公寓租赁运营商:Sun & Snow
2018/10/18 全球购物
英国最大的汽车配件在线商店:Euro Car Parts
2019/09/30 全球购物
Opodo意大利:欧洲市场上领先的在线旅行社
2019/10/24 全球购物
数据员岗位职责
2013/11/19 职场文书
教师个人自我评价范文
2014/04/13 职场文书
法院四风对照检查材料思想汇报
2014/10/06 职场文书
详解MySQL 联合查询优化机制
2021/05/10 MySQL