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错误处理详解
Sep 28 Python
Python Web框架Tornado运行和部署
Oct 19 Python
在Python web中实现验证码图片代码分享
Nov 09 Python
Python带动态参数功能的sqlite工具类
May 26 Python
python os.listdir按文件存取时间顺序列出目录的实例
Oct 21 Python
利用nohup来开启python文件的方法
Jan 14 Python
python 字符串追加实例
Jul 20 Python
wxpython+pymysql实现用户登陆功能
Nov 19 Python
python tkinter GUI绘制,以及点击更新显示图片代码
Mar 14 Python
pytorch 查看cuda 版本方式
Jun 23 Python
如何在vscode中安装python库的方法步骤
Jan 06 Python
python 模拟在天空中放风筝的示例代码
Apr 21 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数组函数序列之array_flip() 将数组键名与值对调
2011/11/07 PHP
PHP中关键字interface和implements详解
2017/06/14 PHP
为Yahoo! UI Extensions Grid增加内置的可编辑器
2007/03/10 Javascript
深入理解javaScript中的事件驱动
2013/05/21 Javascript
引入autocomplete组件时JS报未结束字符串常量错误
2014/03/19 Javascript
js弹出确认是否删除对话框
2014/03/27 Javascript
php读取sqlite数据库入门实例代码
2014/06/25 Javascript
node.js中的fs.lstatSync方法使用说明
2014/12/16 Javascript
Javascript基础教程之switch语句
2015/01/18 Javascript
jQuery toggle 代替方法
2016/03/22 Javascript
jQuery的文档处理程序详解
2016/05/10 Javascript
jquery ajax结合thinkphp的getjson实现跨域的方法
2016/06/06 Javascript
JavaScript中Number对象的toFixed() 方法详解
2016/09/02 Javascript
详解vue 计算属性与方法跟侦听器区别(面试考点)
2018/04/23 Javascript
在vue-cli的组件模板里使用font-awesome的两种方法
2018/09/28 Javascript
微信小程序时间标签和时间范围的联动效果
2019/02/15 Javascript
Nuxt.js实现一个SSR的前端博客的示例代码
2019/09/06 Javascript
利用vue3+ts实现管理后台(增删改查)
2020/10/30 Javascript
[54:09]RNG vs Liquid 2019国际邀请赛淘汰赛 败者组 BO3 第一场 8.23
2019/09/05 DOTA
简单介绍Python中的try和finally和with方法
2015/05/05 Python
Python简单网络编程示例【客户端与服务端】
2017/05/26 Python
Python使用Beautiful Soup爬取豆瓣音乐排行榜过程解析
2019/08/15 Python
Python Collatz序列实现过程解析
2019/10/12 Python
pandas中的ExcelWriter和ExcelFile的实现方法
2020/04/24 Python
Python PyQt5模块实现窗口GUI界面代码实例
2020/05/12 Python
Python生成器next方法和send方法区别详解
2020/05/30 Python
Python的logging模块基本用法
2020/12/24 Python
python字典按照value排序方法
2020/12/28 Python
CSS3 实现的缩略图悬停效果
2020/12/09 HTML / CSS
大学生毕业自荐信
2013/10/10 职场文书
人事科岗位职责范本
2014/03/02 职场文书
个人四风问题对照检查材料
2014/10/01 职场文书
婚宴领导致辞
2015/07/28 职场文书
MongoDB使用场景总结
2022/02/24 MongoDB
动态规划之使用备忘录来改进Javascript函数
2022/04/07 Javascript
Redis Lua脚本实现ip限流示例
2022/07/15 Redis