一、什么是装饰器

装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理等。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。简单来讲,可以不严谨地把Python的装饰器看做一个包装函数的函数。

比如,有一个函数:

  1. def func():
  2. print 'func() run.'
  3.  
  4. if '__main__' == __name__:
  5. func()
  6. 运行后将输出:
  7. func() run

现在需要在函数运行前后打印一条日志, 但是又不希望或者没有权限修改函数内部的结构, 就可以用到装饰器:

  1. def log(function):
  2. def wrapper(*args, **kwargs):
  3. print 'before function [%s()] run.' % function.__name__
  4. rst = function(*args, **kwargs)
  5. print 'after function [%s()] run.' % function.__name__
  6. return rst
  7. return wrapper
  8.  
  9. @log
  10. def func():
  11. print 'func() run.'
  12.  
  13. if '__main__' == __name__:
  14. func()

对于原来的函数"func()"并没有做修改,而是给其使用了装饰器log,运行后的输出为:

  1. before function [func()] run.
  2. func() run.
  3. after function [func()] run.
  4. "@log"放到func()函数定义的地方,相当于执行了如下语句:
  5. func = log(func)

因为log()返回了一个函数, 所以原本的func指向了log()返回的函数wrapper。wrapper的参数列表为(*args, **kwargs), 所以其可以接受所有的参数调用, 在wrapper中,先打印了一行

'before function [%s()] run.' % function.__name__,然后执行了原来的函数并记录了返回值,在输出

'after function [%s()] run.' % function.__name__ ,后返回了函数的执行结果。

以下为示例:

  1. def log(text=''):
  2. def decorator(function):
  3. @functools.wraps(function)
  4. def wrapper(*args, **kwargs):
  5. print 'before function [%s()] run, text: [%s].' % (function.__name__, text)
  6. rst = function(*args, **kwargs)
  7. print 'after function [%s()] run, text: [%s].' % (function.__name__, text)
  8. return rst
  9. return wrapper
  10. return decorator
  11.  
  12. @log('log text')
  13. def func():
  14. print 'func() run.'
  15.  
  16. if '__main__' == __name__:
  17. func()

输出如下:

  1. before function [func()] run, text: [log text].
  2. func() run.
  3. after function [func()] run, text: [log text].

多层装饰器
多重装饰器的应用:当要求每一个代码块需要两个或多个检查时,这样就需要两个或多个装饰器对此代码块进行监督。

下面给出一个使用装饰器同时对代码进行登录和权限的验证:
  1. USER_INFO={'is_login':True,'user_type':''}
  2. def check_login(func):
  3. def inner(*args,**kwargs):
  4. if USER_INFO.get('is_login',None):
  5. ret=func(*args,**kwargs)
  6. return ret
  7. else:
  8. print('没登录')
  9. return inner
  10. def check_admin(func):
  11. def inner(*args,**kwargs):
  12. if USER_INFO.get('user_type',None)==2:
  13. ret=func(*args,**kwargs)
  14. return ret
  15. else:
  16. print('权限不足')
  17. return inner
  18.  
  19. @check_login
  20. @check_admin
  21. def index():
  22. print('管理员')
  23. index()

python中的装饰器的更多相关文章

  1. 简单说明Python中的装饰器的用法

    简单说明Python中的装饰器的用法 这篇文章主要简单说明了Python中的装饰器的用法,装饰器在Python的进阶学习中非常重要,示例代码基于Python2.x,需要的朋友可以参考下   装饰器对与 ...

  2. 【Python】python中的装饰器——@

    对装饰器本来就一知半解的,今天终于弄清楚了,Python中的装饰器是对装饰者模式的很好运用,简化到骨子里了. python中为什么需要装饰器,看这里:http://www.cnblogs.com/hu ...

  3. Python 中实现装饰器时使用 @functools.wraps 的理由

    Python 中使用装饰器对在运行期对函数进行一些外部功能的扩展.但是在使用过程中,由于装饰器的加入导致解释器认为函数本身发生了改变,在某些情况下——比如测试时——会导致一些问题.Python 通过  ...

  4. 写python中的装饰器

    python中的装饰器主要用于在已有函数实现功能前附加需要输出的信息,下面将用实例展示我如何写装饰器. 首先分别尝试写装饰器装饰一个无参函数和一个有参函数(被装饰函数仅输出,无返回值情况下) def ...

  5. python中的装饰器decorator

    python中的装饰器 装饰器是为了解决以下描述的问题而产生的方法 我们在已有的函数代码的基础上,想要动态的为这个函数增加功能而又不改变原函数的代码 例如有三个函数: def f1(x): retur ...

  6. python中@property装饰器的使用

    目录 python中@property装饰器的使用 1.引出问题 2.初步改善 3.使用@property 4.解析@property 5.总结 python中@property装饰器的使用 1.引出 ...

  7. 【Python】解析Python中的装饰器

    python中的函数也是对象,函数可以被当作变量传递. 装饰器在python中功能非常强大,装饰器允许对原有函数行为进行扩展,而不用硬编码的方式,它提供了一种面向切面的访问方式. 装饰器 一个普通的装 ...

  8. 三分钟搞定Python中的装饰器

    python的装饰器是python的特色高级功能之一,言简意赅得说,其作用是在不改变其原有函数和类的定义的基础上,给他们增添新的功能. 装饰器存在的意义是什么呢?我们知道,在python中函数可以调用 ...

  9. python cookbook 学习系列(一) python中的装饰器

    简介 装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象.它经常用于有切面需求的场景,比如:插入日志.性能测试.事务处理.缓 ...

随机推荐

  1. web前端基础篇⑤

    1.雪碧图技术(精灵图)sprite cpmpass-合并2.兼容性:1.reset充值技术,normalize技术2.加前缀-webkit —mom -ms— -o-3.<!Doctype&g ...

  2. General Motors China

    General Motors Co., one of the world's largest automakers, trace its root back to 1908. The General ...

  3. JVM-并发-Java 内存模型

    Java内存模型 (1). 主内存与工作内存 Java内存模型规定了所有的变量都存储在主内存中. 每类线程的变量的主内存副本拷贝,线程对变量的所有操作(读操作,赋值操作等)都必须工作内存中进行,而不能 ...

  4. hdu 2087

    ps:感觉就是字符串处理...好像没什么好讲的...直接上代码 代码: #include "stdio.h" #include "string.h" ]; ]; ...

  5. 关于Let和var声明变量的区别

    Let是ES6中添加进来的一个关键字,用于声明变量,其法与var声明变量相同,不同点在于其作用域(块级). 举例可以看出其具体差别 for(var i=0;i<5;i++){ console.l ...

  6. OD调试篇12

    Delphi的逆向 先看看今天需要破解的程序. 打开程序先出现了一个nag窗口,然后是unregistered未注册的提示,以及关于里的需要注册. 拖进die看了看      就是delphi写的.那 ...

  7. Gym 100851K

    Problem King's Inspection 题目大意 给一张n个点m条边的无向图,问是否存在一条欧拉回路. n<=10^5, 0<=m<=n+20. 解题分析 注意到数据范围 ...

  8. div高度自适应(总结:min-height:100px; height:auto;的用法)

    对于div高度自适应问题,我总是用一句话:height:auto来解决. 但是很多时候我们需要的是当div内部有内容时,高度会随着内容的增加和增加,当div中没有内容时,div能够保持一个固定的高度. ...

  9. [转]http://makefiletutorial.com/

    Intro This makefile will always run. The default target is some_binary, because it is first. some_bi ...

  10. php-访问数据库

    建一个连接,造一个连接对象 $db = new MySQLi("host","username","passwd","databa ...