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中封装GObject模块进行图形化程序编程的教程
Apr 14 Python
python追加元素到列表的方法
Jul 28 Python
python制作爬虫并将抓取结果保存到excel中
Apr 06 Python
Python读写txt文本文件的操作方法全解析
Jun 26 Python
Python实现获取本地及远程图片大小的方法示例
Jul 21 Python
opencv python 基于KNN的手写体识别的实例
Aug 03 Python
python K近邻算法的kd树实现
Sep 06 Python
Python如何处理大数据?3个技巧效率提升攻略(推荐)
Apr 15 Python
python安装virtualenv虚拟环境步骤图文详解
Sep 18 Python
Python网络编程之使用TCP方式传输文件操作示例
Nov 01 Python
在pycharm中debug 实时查看数据操作(交互式)
Jun 09 Python
Python利用命名空间解析XML文档
Aug 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实现读取一个1G的文件大小
2013/08/24 PHP
php使用substr()和strpos()联合查找字符串中某一特定字符的方法
2015/05/12 PHP
PHP 配置后台登录以及模板引入
2017/01/24 PHP
thinkphp查询,3.X 5.0方法(亲试可行)
2017/06/17 PHP
PHP设计模式之装饰器模式实例详解
2018/02/07 PHP
thinkphp5框架结合mysql实现微信登录和自定义分享链接与图文功能示例
2019/08/13 PHP
Script标签与访问HTML页面详解
2014/01/10 Javascript
js实现俄罗斯方块小游戏分享
2014/01/31 Javascript
基于jQuery+Cookie实现的防止刷新的在线考试倒计时
2015/06/19 Javascript
javascript类型系统 Window对象学习笔记
2016/01/07 Javascript
jquery siblings获取同辈元素用法实例分析
2016/07/25 Javascript
JS 中可以提升幸福度的小技巧(可以识别更多另类写法)
2018/07/28 Javascript
node实现生成带参数的小程序二维码并保存到本地功能示例
2018/12/05 Javascript
jQuery移动端跑马灯抽奖特效升级版(抽奖概率固定)实现方法
2019/01/18 jQuery
使用element-ui table expand展开行实现手风琴效果
2019/03/15 Javascript
基于 vue-skeleton-webpack-plugin 的骨架屏实战
2019/08/05 Javascript
解决layui的input独占一行的问题
2019/09/10 Javascript
原生js实现二级联动菜单
2019/11/27 Javascript
javascript实现支付宝滑块验证码效果
2020/07/24 Javascript
[55:16]Mski vs VGJ.S Supermajor小组赛C组 BO3 第二场 6.3
2018/06/04 DOTA
python实现socket端口重定向示例
2014/02/10 Python
Python接收Gmail新邮件并发送到gtalk的方法
2015/03/10 Python
Python多线程编程(七):使用Condition实现复杂同步
2015/04/05 Python
Python爬取网页中的图片(搜狗图片)详解
2017/03/23 Python
基于Python和C++实现删除链表的节点
2020/07/06 Python
html5的新玩法——语音搜索
2013/01/03 HTML / CSS
利用HTML5绘制点线面组成的3D图形的示例
2015/05/12 HTML / CSS
大学自我鉴定范文
2013/12/26 职场文书
个人简历自我评价
2014/01/06 职场文书
海飞丝广告词
2014/03/20 职场文书
营销与策划专业求职信
2014/06/20 职场文书
住房抵押登记委托书
2014/09/27 职场文书
2015新年联欢晚会开场白
2014/12/14 职场文书
先进教师个人主要事迹材料
2015/11/03 职场文书
2016年教师学习廉政准则心得体会
2016/01/20 职场文书
集英社今正式宣布 成立游戏公司“集英社Games”
2022/03/31 其他游戏