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 相关文章推荐
在MAC上搭建python数据分析开发环境
Jan 26 Python
Python列表推导式与生成器表达式用法示例
Feb 08 Python
python中kmeans聚类实现代码
Feb 23 Python
对pandas中apply函数的用法详解
Apr 10 Python
python使用Matplotlib绘制分段函数
Sep 25 Python
pycham查看程序执行的时间方法
Nov 29 Python
利用python如何在前程无忧高效投递简历
May 07 Python
python命名空间(namespace)简单介绍
Aug 10 Python
Python 实现毫秒级淘宝抢购脚本的示例代码
Sep 16 Python
python 魔法函数实例及解析
Sep 25 Python
Python安装tar.gz格式文件方法详解
Jan 19 Python
用Python爬虫破解滑动验证码的案例解析
May 06 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获取网页内容方法总结
2008/12/04 PHP
PHP 文章中的远程图片采集到本地的代码
2009/07/30 PHP
完美解决PHP中文乱码
2009/11/26 PHP
php中使用redis队列操作实例代码
2013/02/07 PHP
php对xml文件的增删改查操作实现方法分析
2017/05/19 PHP
简单实用jquery版三级联动select示例
2013/07/04 Javascript
jQuery如何获取同一个类标签的所有值(默认无法获取)
2014/09/25 Javascript
JQuery工具函数汇总
2015/06/15 Javascript
jquery平滑滚动到顶部插件使用详解
2017/05/08 jQuery
javascript完美实现给定日期返回上月日期的方法
2017/06/15 Javascript
JavaScript 完成注册页面表单校验的实例
2017/08/19 Javascript
Vue 滚动行为的具体使用方法
2017/09/13 Javascript
vue.js项目打包上线的图文教程
2017/11/16 Javascript
AngularJS实时获取并显示密码的方法
2018/02/06 Javascript
详解webpack loader和plugin编写
2018/10/12 Javascript
详解vue在项目中使用百度地图
2019/03/26 Javascript
vue项目中在外部js文件中直接调用vue实例的方法比如说this
2019/04/28 Javascript
新手快速入门JavaScript装饰者模式与AOP
2019/06/24 Javascript
Node.js实现简单的爬取的示例代码
2019/06/25 Javascript
Vue.js 中制作自定义选择组件的代码附演示demo
2020/02/28 Javascript
webpack 动态批量加载文件的实现方法
2020/03/19 Javascript
[02:53]DOTA2英雄基础教程 山岭巨人小小
2013/12/09 DOTA
[00:39]DOTA2上海特级锦标赛 Liquid战队宣传片
2016/03/04 DOTA
Python文件操作基本流程代码实例
2017/12/11 Python
Python 给某个文件名添加时间戳的方法
2018/10/16 Python
Python通用函数实现数组计算的方法
2019/06/13 Python
如何使用python自带IDLE的几种方法
2020/10/10 Python
管理部部长岗位职责
2013/12/05 职场文书
应用化学专业职业生涯规划书
2014/01/22 职场文书
出国英文推荐信
2014/05/10 职场文书
村容村貌整治方案
2014/05/21 职场文书
民政局副局长民主生活会个人对照检查材料
2014/09/19 职场文书
2015年财务部年度工作总结
2015/05/19 职场文书
总结Python变量的相关知识
2021/06/28 Python
Python实现老照片修复之上色小技巧
2021/10/16 Python
Golang jwt身份认证
2022/04/20 Golang