函数是个对象,并且可以赋值给一个变量,通过变量也能调用该函数:

>>> def now():
... print('2017-12-28')
...
>>> l = now
>>> l()
2017-12-28

利用函数的_name_属性,可以拿到函数的名字:

>>> now.__name__
'now'
>>> l.__name__
'now'

如果我们在调用函数now()前后自动打印日志,但又不允许修改now()函数的定义——在代码运行期间动态增加功能的方式,称之为‘装饰器’Decorator。

比如,定义一个能打印日志的decorator:

>>> def log(func):
... def wrapper(*args,**kw):
... print('call %s():' % func.__name__)
... return func(*args,**kw)
... return wrapper
...

观察log 函数,发现,本质上这就是一个返回函数的高阶函数!log作为一个decorator,接收一个函数作为参数,冰饭一个函数。借助python的@语法,把decorator置于函数的定义的地方:

>>> @log
... def now():
... print('2017-12-28')
...
>>> now()
call now():
2017-12-28

在调用now()函数时候,不仅运行了now函数,还会在此之前打印一行日志。

其实,把@log放到now()函数的定义前,相当于执行了:

now = log(now)

log是一个decorator,返回一个函数,返回的这个函数名字叫wrapper,原来的now()函数还存在,这个时候now变量指向了这个返回函数wrapper。当调用now()将执行新的函数wrapper函数。wrapper函数的参数是(*args,**kw),因此wrapper()函数可以接受任意参数!在wrapper函数内部,首先打印日志,再紧接着调用原始函数。

分割线-------------------------------

如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数。比如要自定义log的文本,定义、用法和结果:

>>> def log(text):
... def decorator(func):
... def wrapper(*args,**kw):
... print('%s %s():' %(text,func.__name__))
... return func(*args,**kw)
... return wrapper
... return decorator
...
>>> @log('执行')
... def now():
... print('2017-12-28')
...
>>> now()
执行 now():
2017-12-28

前面的例子中包含了两层def嵌套,后面的例子中包含了三层def嵌套。其实,三层嵌套的效果类似:

now = log('执行')(now)

解析:首先执行log('执行'),返回的是decorator函数,再调用返回函数,参数是now函数,最终的返回值是wrapper函数。

但是,我们执行下面语句来测试:

>>> now.__name__
'wrapper'

我们发现:经过decorator装饰后的函数,他们的__name__属性已经从now变成了wrapper。这是因为返回的那个函数wrapper函数名字就是wrapper,所以,需要把原始函数的__name__属性复制到wrapper函数中,否则,其他一些依赖函数签名的代码执行就会报错。

实际上我们并不需要编写wrapper.__name__ = func.__name__这样的代码,python内置了functools.wraps就是为了这个。最

最后一步,一个完整的decorator的写法如下:

>>> import functools
>>> def log(func):
... @functools.wraps(func)
... def wrapper(*args,**kw):
... print('执行 %s()' %func.__name__)
... return func(*args,**kw)
... return wrapper
...
>>> @log
... def now():
... print('日志')
...
>>> now
<function now at 0x03317198>
>>> now()
执行 now()
日志

针对带有参数的decorator:

>>> import functools
>>> def log(text):
... def decorator(func):
... @functools.wraps(func)
... def wrapper(*args,**kw):
... print('%s %s()' %(text,func.__name__))
... return func(*args,**kw)
... return wrapper
... return decorator
...
>>> @log('ABC')
... def now():
... print('这么复杂干嘛')
...
>>> now()
ABC now()
这么复杂干嘛

例子:设计一个decorator,可作用于任何函数上,并打印该函数的执行时间:

>>> import time,functools
>>> def log(func):
... @functools.wraps(func)
... def wrapper(*args,**kw):
... t1 = time.time()
... r = func(*args,**kw)
... print('%s excute in %s ms'%(func.__name__,1000*(time.time()-t1)))
... return r
... return wrapper
...
>>> @log
... def fast(x,y):
... return x+y
...
>>> @log
... def slow(x,y,z):
... time.sleep(0.1234)
... return x*y*z
...
>>> @log
... def fast(x,y):
... time.sleep(0.0012)
... return x+y
...
>>> fast(3,5)
fast excute in 2.0973682403564453 ms
8
>>> slow(4,5,6)
slow excute in 124.2520809173584 ms
120

python函数编程-装饰器decorator的更多相关文章

  1. python 深入浅出装饰器(decorator)--举的例子关于星级争霸2(starcraft2)

    其实早就想写一篇深入浅出装饰器的文章,苦于一直没有找到很好的例子描述,自己除了在写api参数检测和日志打印的时候用到以外,其他地方也没有什么重度使用所以一直没有写. 我不会讲解装饰器的理论,还有各种基 ...

  2. 详解python的装饰器decorator

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

  3. 关于Python的装饰器 decorator

    装饰器的原理:其实就是高阶函数,接收原函数以在之前之后进行操作. 语法格式是固定的:先定义一个函数,再使用@语法调用该函数. 例子一: import functools # 定义装饰器,固定格式 de ...

  4. Python学习——装饰器/decorator/语法糖

    装饰器 定义:本质是函数,为其他函数添加附加的功能. 原则:1.不能修改原函数的源代码 2.不能修改被原函数的调用方式 重点理解: 1.函数即“变量” 2.高阶函数:返回值中包含函数名 3.嵌套函数 ...

  5. 关于python的装饰器(初解)

    在python中,装饰器(decorator)是一个主要的函数,在工作中,有了装饰器简直如虎添翼,许多公司面试题也会考装饰器,而装饰器的意思又很难让人理解. python中,装饰器是一个帮函数动态增加 ...

  6. python 装饰器(decorator)

    装饰器(decorator) 作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 装饰器(decorator)是一种高级Python语 ...

  7. python之装饰器(decorator)

    python的装饰器如果用得好,那是大神,用的不好最好别用... 装饰器(decorator)主要包含俩大属性: 1.不能改变原有函数的调用方式 2.不能改变原有函数的代码 第一个表示,我不需要改变原 ...

  8. python语法32[装饰器decorator](转)

    一 装饰器decorator decorator设计模式允许动态地对现有的对象或函数包装以至于修改现有的职责和行为,简单地讲用来动态地扩展现有的功能.其实也就是其他语言中的AOP的概念,将对象或函数的 ...

  9. python 语法之 装饰器decorator

    装饰器 decorator 或者称为包装器,是对函数的一种包装. 它能使函数的功能得到扩充,而同时不用修改函数本身的代码. 它能够增加函数执行前.执行后的行为,而不需对调用函数的代码做任何改变. 下面 ...

随机推荐

  1. 【nodejs原理&源码杂记(8)】Timer模块与基于二叉堆的定时器

    [摘要] timers模块部分源码和定时器原理 示例代码托管在:http://www.github.com/dashnowords/blogs 一.概述 Timer模块相关的逻辑较为复杂,不仅包含Ja ...

  2. 【跟唐老师学习云网络】 - 第7篇 Tcpdump大杀器抓包

    [摘要] 前面章节的网络协议栈相关的信息建议大家多学习一遍,因为这些都是最基础的东西,想玩好云网络必备基本功.. 一.上帝视角 之前提到过定位问题可以开启上帝视角,那么如何开启就要依靠tcpdump这 ...

  3. 转:MySQL下载安装、配置与使用(win7x64)

    1 第一大步:下载. a.俗话说:“巧妇难为无米之炊”嘛!我这里用的是 ZIP Archive 版的,win7 64位的机器支持这个,所以我建议都用这个.因为这个简单嘛,而且还干净. 地址见图 拉倒最 ...

  4. windows下利用iis建立网站网站并实现局域共享

    博客园 首页 新随笔 联系 管理 订阅 随笔- 54  文章- 9  评论- 0  Windows下利用IIS建立网站并实现局域网共享 https://blog.csdn.net/qq_4148541 ...

  5. 遍历json数据的几种方式。

    json(JavaScript Object Notation),json是一种多用于存储和交换文本信息的语法.他能够进行数据的传输,通常和ajax一起使用.它具有体积小.速度快,易解析等诸多优点. ...

  6. Java修炼——线程同步的俩种方法

    当多线程去同时抢占CPU资源时,有多线程的安全问题.这时候就需要将线程同步.线程同步有俩个方法. 1.同步代码块(synchronize),同步代码块需要同步监视器,同步监视器是针对对象进行操作.什么 ...

  7. [知也无涯]GAN对人脸算法的影响

    红绣被,两两间鸳鸯.不是鸟中偏爱尔,为缘交颈睡南塘.全胜薄情郎. 看到一篇GAN对人脸图像算法的影响,决心学习一个. 人脸检测 这也是我最关注的模块.文章推荐了极小面部区域人脸识别Finding ti ...

  8. Task 的一些个人见解

    Task确实比较好用且优雅 我感觉.NET要成为艺术家... public class TheTask { /// <summary> /// 直接调用是同步方法 /// </sum ...

  9. Django ContentType 的使用

    引入 一切优化,最终都是关于需求的优化.本文介绍需求确定之后的数据库表结构设计优化. 程序员应该都知道,编程是数据结构和算法的结合.所谓数据就是用户需要访问和操作的资源,比如购物类App里面的商品,图 ...

  10. JS-变量、作用域、垃圾回收机制总结

    预解析时变量和函数同名的话,保留函数