引言:

  装饰器是python面向对象编程三大器之一,另外两个迭代器、生成器只是我现在还没有遇到必须使用的场景,等确实需要用到的时候,在补充资料;装饰器在某些场景真的是必要的,比如定义了一个类或者一个函数,在后面的编程过程中发现需要对定义好的类增加一些功能;或者说有一些功能是某一类函数公用的功能,可以将这个功能做成装饰器来装饰这一类功能;场景还有很多,先来大体了解下装饰器的创建以及基本的实现原理;

文章来源:

http://blog.csdn.net/TangHuanan/article/details/45094497

正文:

刚看到Python装饰器时, 觉得很神奇。简单实验下,发现也就那么回事。但是慢慢的看到越来越多的装饰器。很多时候又不了解到底是怎么回事了。

最后还是决定好好研究下。

先看看一些实例, 然后再来分析下原理 
假设我们有如下的基本函数

def do_something():for i in range(1000000):passprint "play game"do_something()

结果如下:

play game

需求1: 统计函数的执行时间

1. 不是装饰器的装饰器

import time
def decorator(fun):start = time.time()fun()runtime = time.time()-startprint runtimedef do_something():for i in range(1000000):passprint "play game"decorator(do_something)

结果如下:

play game
0.0299999713898

这种实现看上去还可以,但是每次调用的是decorator,还要把函数作为一个参数传入。这样需要修改调用的地方,使用起来就不方便了。

2. 最简单的装饰器

import time
def decorator(fun):def wrapper():start = time.time()fun()runtime = time.time()-startprint runtimereturn wrapper
@decorator
def do_something():for i in range(1000000):passprint "play game"do_something()

结果如下:

play game
0.0329999923706

装饰器是在函数定义时前面加@,然后跟装饰器的实现函数。可以看出,现在只要直接调用do_something就可以了。调用的地方不要作任何修改。

3. 目标函数带固定参数的装饰器

import time
def decorator(fun):def wrapper(name):start = time.time()fun(name)runtime = time.time()-startprint runtimereturn wrapper
@decorator
def do_something(name):for i in range(1000000):passprint "play game " + namedo_something("san guo sha")

结果如下:

play game san guo sha
0.039999961853

实现很简单, 就是给wrapper函数参加相同的参数

4. 目标函数带不固定参数的装饰器

import time
def decorator(fun):def wrapper(*args, **kwargs):start = time.time()fun(*args, **kwargs)runtime = time.time()-startprint runtimereturn wrapper
@decorator
def do_something(name):for i in range(1000000):passprint "play game " + name@decorator
def do_something2(user, name):for i in range(1000000):passprint user+" play game " + namedo_something("san guo sha")
do_something2("wang xiao er","san guo sha")

结果如下:

play game san guo sha
0.029000043869
wang xiao er play game san guo sha
0.0310001373291

需求2: 目标函数每次调用重复执行指定的次数

5. 让装饰器带参数

import time
def decorator(max):def _decorator(fun):def wrapper(*args, **kwargs):start = time.time()for i in xrange(max):fun(*args, **kwargs)runtime = time.time()-startprint runtimereturn wrapperreturn _decorator
@decorator(2)
def do_something(name):for i in range(1000000):passprint "play game " + namedo_something("san guo sha")

结果如下:

play game san guo sha
play game san guo sha
0.0600001811981

6. 原理

看了这么多实例, 装饰器的基本类型也基本上都有了。是不是清楚了呢? 
如果还是不清楚,那就继续看下面的内容。

1 不带参数的装饰器

@a_decorator
def f(...):...#经过a_decorator后, 函数f就相当于以f为参数调用a_decorator返回结果。
f = a_decorator(f)

来分析这个式子, 可以看出至少要满足以下几个条件 
1. 装饰器函数运行在函数定义的时候 
2. 装饰器需要返回一个可执行的对象 
3. 装饰器返回的可执行对象要兼容函数f的参数

2 验证分析

1 装饰器运行时间

import time
def decorator(fun):print "decorator"def wrapper():print "wrapper"start = time.time()fun()runtime = time.time()-startprint runtimereturn wrapper
@decorator
def do_something():for i in range(1000000):passprint "play game"

结果如下:

decorator

可以看出, 这里的do_something并没有调用, 但是却打印了decorator, 可wrapper没有打印出来。也就是说decorator是在do_something调用的时候执行的。

2 返回可执行的对象

import time
def decorator(fun):print "decorator"def wrapper():print "wrapper"start = time.time()fun()runtime = time.time()-startprint runtimereturn None
@decorator
def do_something():for i in range(1000000):passprint "play game"do_something()

结果如下:

decoratorTraceback (most recent call last):File "deco.py", line 17, in <module>do_something()
TypeError: 'NoneType' object is not callable

3 兼容函数f的参数

import time
def decorator(fun):print "decorator"def wrapper():print "wrapper"start = time.time()fun()runtime = time.time()-startprint runtimereturn wrapper
@decorator
def do_something(name):for i in range(1000000):passprint "play game"do_something("san guo sha")

结果如下:

decoratorTraceback (most recent call last):File "deco.py", line 17, in <module>do_something("san guo sha")
TypeError: wrapper() takes no arguments (1 given)

看到这里, 至少对不带参数的装饰器应该全弄清楚了, 也就是说能到看山还是山了。

3 带参数的装饰器

这里就给一个式子, 剩下的问题可以自己去想

@decomaker(argA, argB, ...)
def func(arg1, arg2, ...):pass
#这个式子相当于
func = decomaker(argA, argB, ...)(func)

4 被装饰过的函数的函数名

import time
def decorator(fun):def wrapper():start = time.time()fun()runtime = time.time()-startprint runtimereturn wrapper
@decorator
def do_something():print "play game"print do_something.__name__

结果如下:

wrapper

可以看出, do_something的函数名变成了wrapper,这不是我们想要的。原因估计各位也都清楚了。那要怎么去解决呢?

import time
def decorator(fun):def wrapper():start = time.time()fun()runtime = time.time()-startprint runtimewrapper.__name__ = fun.__name__return wrapper
@decorator
def do_something():print "play game"print do_something.__name__

结果如下:

do_something

但是这个看起来是不是很不专业, python的unctools.wraps提供了解决方法

import time
import functools
def decorator(fun):@functools.wraps(fun)def wrapper():start = time.time()fun()runtime = time.time()-startprint runtimereturn wrapper
@decorator
def do_something():print "play game"print do_something.__name__

结果如下:

do_something

到此为止, 你是不是觉得已经完全明白了呢? 
但事实是, 这其实还不够

7. 装饰器类

需求3: 让函数只能运行指定的次数 
前面我们讲的都是函数式的装饰器, 那么类能不能成为装饰器呢?

import time
import functools class decorator(object):def __init__(self, max):self.max = maxself.count = 0def __call__(self, fun):self.fun = funreturn self.call_fundef call_fun(self, *args, **kwargs):self.count += 1if ( self.count == self.max):print "%s run more than %d times"%(self.fun.__name__, self.max)elif (self.count<self.max):self.fun(*args, **kwargs)else:pass@decorator(10)
def do_something():print "play game"
@decorator(15)
def do_something1():print "play game 1"
for i in xrange(20):do_something()do_something1()

结果如下:

play game
play game 1
play game
play game 1
play game
play game 1
play game
play game 1
play game
play game 1
play game
play game 1
play game
play game 1
play game
play game 1
play game
play game 1
do_something run more than 10 times
play game 1
play game 1
play game 1
play game 1
play game 1
do_something1 run more than 15 times

是不是感觉有点怪, 但它确实是可行的。 
在Python中, 其实函数也是对象。 反过来, 对象其实也可以像函数一样调用, 只要在类的方法中实现__call__方法。回想一下创建对象的过程

class A:def __init__(self):pass
a = A()

这其实和函数调用没什么区别, 那么把这个式子代入到之前两个装饰器的式子中,结果如下: 
带参数的装饰器 
fun = A.__init__(args)(fun) 
不带参数的装饰器 
fun = A.__init__(fun)()

现在装饰器的内容基本差不多了。 还有一些问题, 可以自己去尝试研究。

还有几个问题如下: 
1. 类装饰器(装饰器装饰的对象是类) 
2. 类函数装饰器(装饰器装饰的对象是类的函数) 
3. 多个装饰器一起使用(函数嵌套)

转载于:https://www.cnblogs.com/zanjiahaoge666/p/7478962.html

python装饰器(docorator)详解相关推荐

  1. python装饰器详解-Python装饰器基础详解

    装饰器(decorator)是一种高级Python语法.装饰器可以对一个函数.方法或者类进行加工.在Python中,我们有多种方法对函数和类进行加工,比如在Python闭包中,我们见到函数对象作为某一 ...

  2. python装饰器(详解)

    大家好,我是J哥. 今天我们介绍一下python中的装饰器 首先我们要了解什么是装饰器 1.什么是装饰器 器指的是工具,可以定义成成函数 装饰指的是为其他事物添加额外的东西点缀 合到一起的解释:装饰器 ...

  3. 设计模式之装饰器模式详解

    设计模式之装饰器模式详解 文章目录 设计模式之装饰器模式详解 一.什么是装饰器模式 二.装饰器模式的角色组成 三.装饰器模式通用写法示例 四.装饰器模式业务中的应用举例 五.装饰器模式优缺点 一.什么 ...

  4. python装饰器作用和功能_python装饰器大详解

    一.作用域 在python中,作用域分为两种:全局作用域和局部作用域. 全局作用域是定义在文件级别的变量,函数名.而局部作用域,则是定义函数内部. 关于作用域,我们要理解两点: a.在全局不能访问到局 ...

  5. python装饰器class_Python装饰器dataclass详解

    引言 Dataclasses 是一些适合于存储数据对象(data object)的 Python类.你可能会问,什么是数据对象?下面是一个并不详尽的用于定义数据对象的特征列表: 他们存储并表示特定的数 ...

  6. python3.7用法_Python 3.7中dataclass装饰器用法详解

    Python 3.7的dataclass装饰器用法 Python 3.7新功能之dataclass装饰器详解 前言 Python 3.7 将于今年夏天发布,Python 3.7 中将会有许多新东西: ...

  7. Python装饰器之property()详解

    1. 何为装饰器? 官方定义:装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志.性能测试.事务处理等.装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数 ...

  8. (十)装饰器模式详解(与IO不解的情缘)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处. LZ到目前已经写了九个设计模式,回过去看看,貌似写的有点凌乱,LZ后面会尽量改进. 那么本章LZ和各位读友讨论一个与JAVA中IO有着 ...

  9. Java 装饰器模式详解

    转载请注明出处:http://blog.csdn.net/zhaoyanjun6/article/details/56488020 前言 在上面的几篇文章中,着重介绍了java 中常见的 IO 相关知 ...

  10. Java装饰器模式详解

    前言 装饰器模式也叫做包装器模式,属于结构性设计模式一种,装饰器设计模式在实际的生活中也有很多体现,举例来说,某手机厂商发布了XXX标准版手机,为了吸引用户眼球,提升销量,还特别有纪念碑,青春版,至尊 ...

最新文章

  1. 我开发共享软件的三次经历(中):我赚到了十万块
  2. oracle常用sql命令
  3. [转]Apache Commons IO入门教程
  4. 【转】C++ this指针(直戳本质)
  5. flask处理cookie
  6. win7无法打开设备和打印机
  7. 腾讯二面:@Bean 与 @Component 用在同一个类上,会怎么样?
  8. SSL 1887——潜伏者
  9. 【微软2014实习生及秋令营技术类职位在线測试】题目2 : K-th string
  10. VC6.0内存泄露检测工具
  11. 苹果手机计算机记录,苹果手机怎么查找以前的历史通话记录
  12. 中兴olt xpon开局及业务配置以及原理
  13. eyebeam电话呼叫软件使用及配置方法
  14. VBS调用ping检测ip连通情况
  15. 王者荣耀 微信登录 服务器找不到,王者荣耀微信无法登录是怎么回事 具体解决方法...
  16. 谷歌10年,难说再见......
  17. 杜拉拉职场速腾三十六招
  18. 大学物理 复习指导、公式推导精简过程、结论归纳 第一章 质点运动学
  19. HTML【表单和输入(按钮+登陆框)+框架】
  20. 数值分析——Gauss-Legendre 求积分(Matlab实现)

热门文章

  1. PHP移动互联网开发笔记(6)——MySQL数据库基础回想
  2. Docker网络实践运用
  3. hihoCoder #1349 Nature Numbers
  4. Nature:新发现挑战神经元作用传统理论 [转自科学网]
  5. javascript基础知识系列:eval()
  6. 聊聊kafka consumer offset lag的监控
  7. Swarm Mode服务管理
  8. 构建之法第四章学习心得
  9. linux内核分析作业8:理解进程调度时机跟踪分析进程调度与进程切换的过程
  10. ORA-01031:insufficient privileges