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中使用mysql数据库详细介绍
Mar 27 Python
Python3.2中的字符串函数学习总结
Apr 23 Python
Flask框架响应、调度方法和蓝图操作实例分析
Jul 24 Python
Python 读写文件的操作代码
Sep 20 Python
Django ManyToManyField 跨越中间表查询的方法
Dec 18 Python
Python实现读取txt文件中的数据并绘制出图形操作示例
Feb 26 Python
django2笔记之路由path语法的实现
Jul 17 Python
django商品分类及商品数据建模实例详解
Jan 03 Python
Python中求对数方法总结
Mar 10 Python
Python线程协作threading.Condition实现过程解析
Mar 12 Python
python 自定义异常和主动抛出异常(raise)的操作
Dec 11 Python
pytorch 梯度NAN异常值的解决方案
Jun 05 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下获取客户端ip地址的函数
2010/03/15 PHP
php json_encode值中大括号与花括号区别
2013/09/30 PHP
PHP中include/require/include_once/require_once使用心得
2016/08/28 PHP
php unlink()函数使用教程
2018/07/12 PHP
javascript下function声明一些小结
2007/12/28 Javascript
javascript 表单规则集合对象
2009/07/21 Javascript
jquery ajax实现下拉框三级无刷新联动,且保存保持选中值状态
2013/10/29 Javascript
JS获取单击按钮单元格所在行的信息
2014/06/17 Javascript
浅谈jquery的map()和each()方法
2016/06/12 Javascript
JavaScript设计模式之单体模式全面解析
2016/09/09 Javascript
轻松实现js弹框显示选项
2016/09/13 Javascript
jQuery密码强度验证控件使用详解
2017/01/05 Javascript
详解webpack分包及异步加载套路
2017/06/29 Javascript
js轮播图的插件化封装详解
2017/07/17 Javascript
Vue2.0结合webuploader实现文件分片上传功能
2018/03/09 Javascript
vue.js 添加 fastclick的支持方法
2018/08/28 Javascript
vue项目中使用vue-i18n报错的解决方法
2019/01/13 Javascript
vue项目中监听手机物理返回键的实现
2020/01/18 Javascript
python计算最大优先级队列实例
2013/12/18 Python
用Python制作在地图上模拟瘟疫扩散的Gif图
2015/03/31 Python
Python实现把xml或xsl转换为html格式
2015/04/08 Python
Python实现的摇骰子猜大小功能小游戏示例
2017/12/18 Python
基于Python实现拆分和合并GIF动态图
2019/10/22 Python
Python分类测试代码实例汇总
2020/07/23 Python
python调用摄像头的示例代码
2020/09/28 Python
python中字符串的编码与解码详析
2020/12/03 Python
CSS3 中的@keyframes介绍
2014/09/02 HTML / CSS
船舶专业个人求职信范文
2014/01/02 职场文书
淘宝网店营销策划书
2014/01/11 职场文书
期末自我鉴定
2014/01/23 职场文书
《窗前的气球》教学反思
2014/04/07 职场文书
保研推荐信
2014/05/09 职场文书
社会稳定风险评估方案
2014/06/02 职场文书
反腐倡廉观后感
2015/06/08 职场文书
婚宴来宾致辞
2015/07/28 职场文书
领导激励员工的演讲稿,各种会上用得到,建议收藏
2019/08/13 职场文书