如何实现一个python函数装饰器(Decorator)


Posted in Python onOctober 12, 2020

装饰器本质上是一个 Python 函数或类,它可以让其他函数或类在不需要做任何代码修改的前提下增加额外功能,装饰器的返回值也是一个函数/类对象。它经常用于为已有函数/类添加记录日志、计时统计、性能测试等。

首先定义一个倒计时函数,这个函数的功能非常简单,就是把n从当前值减少到0。

def countdown(n):
 while n > 0:
  print('time' + str(n))
  n -= 1

print(countdown.__name__)

程序输出:

countdown

1.为函数增加一个日志装饰器

假设现在要增强countdown的功能,在函数调用前后自动打印日志,又不想修改函数自身的功能。这种在代码运行期间动态增加功能的方式,称之为装饰器(Decorator)。

能打印日志的decorator,可以定义如下:

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

然后我们借助Python的@语法,把decorator置于函数的定义处:

@log
def countdown(n):
 while n > 0:
  print('time:' + str(n))
  n -= 1

countdown(10)

程序输出:

call countdown().
time:10
time:9
time:8
time:7
time:6
time:5
time:4
time:3
time:2
time:1

但此时我们再打印函数的name:

print(countdown.__name__)

程序输出:

wrapper

我们发现函数的元数据信息变了,这显然不是我们想要的结果。

2. 在装饰器中拷贝元数据

为了把函数的元数据信息都保留下来,我们可以直接使用Python提供的functools库中的@wraps装饰器。

from functools import wraps

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

@log
def countdown(n):
 while n > 0:
  print('time:' + str(n))
  n -= 1

print(countdown.__name__)

程序输出:

countdown

3.为函数增加一个计时装饰器

添加函数装饰器的方法已经讲清楚了,现在再实现一个完整的函数计时耗时装饰器。

import time
from functools import wraps

def TimeCost(func):
 @wraps(func)
 def wrapper(*arg, **kwargs):
  start = time.time()
  result = func(*args, **kwargs)
  end = time.time()
  print(func.__name__, end - start)
  return result
 return wrapper

@TimeCost
def countdown(n):
 while n > 0:
  print('time:' + str(n))
  n -= 1

countdown(10000)

函数输出:

('countdown', 0.0004801750183105469)

参考资料:

以上就是如何实现一个python函数装饰器(Decorator)的详细内容,更多关于python函数装饰器的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
初步解析Python中的yield函数的用法
Apr 03 Python
Python全局变量操作详解
Apr 14 Python
浅谈python中scipy.misc.logsumexp函数的运用场景
Jun 23 Python
PyQt5实现无边框窗口的标题拖动和窗口缩放
Apr 19 Python
通过python的matplotlib包将Tensorflow数据进行可视化的方法
Jan 09 Python
详解Python用户登录接口的方法
Apr 17 Python
python tkinter canvas使用实例
Nov 04 Python
Python中import导入不同目录的模块方法详解
Feb 18 Python
python数据分析工具之 matplotlib详解
Apr 09 Python
python 实现 hive中类似 lateral view explode的功能示例
May 18 Python
看看如何用Python绘制小米新版天价logo
Apr 20 Python
python实现局部图像放大
Nov 17 Python
Vs Code中8个好用的python 扩展插件
Oct 12 #Python
Django中和时区相关的安全问题详解
Oct 12 #Python
python调用有道智云API实现文件批量翻译
Oct 10 #Python
python线程池 ThreadPoolExecutor 的用法示例
Oct 10 #Python
python开发一款翻译工具
Oct 10 #Python
Python pickle模块常用方法代码实例
Oct 10 #Python
Python3.9新特性详解
Oct 10 #Python
You might like
PHP header函数分析详解
2011/08/06 PHP
深入理解PHP之数组(遍历顺序)  Laruence原创
2012/06/13 PHP
Yii清理缓存的方法
2016/01/06 PHP
基于thinkPHP类的插入数据库操作功能示例
2017/01/06 PHP
Yii2配置Nginx伪静态的方法
2017/05/05 PHP
php实现对文件压缩简单的方法
2019/09/29 PHP
php面试实现反射注入的详细方法
2019/09/30 PHP
jquery 入门教程 [翻译] 推荐
2009/08/17 Javascript
js用typeof方法判断undefined类型
2014/07/15 Javascript
Express.JS使用详解
2014/07/17 Javascript
原生js实现的贪吃蛇网页版游戏完整实例
2015/05/18 Javascript
从重置input file标签中看jQuery的 .val() 和 .attr(“value”) 区别
2016/06/12 Javascript
JavaScript正则替换HTML标签功能示例
2017/03/02 Javascript
JS得到当前时间的方法示例
2017/03/24 Javascript
javascript简写常用的12个技巧(可以大大减少你的js代码量)
2020/03/28 Javascript
使用vue的v-for生成table并给table加上序号的实例代码
2017/10/27 Javascript
JavaScript实现AOP详解(面向切面编程,装饰者模式)
2017/12/19 Javascript
详解React中setState回调函数
2018/06/14 Javascript
vue二级菜单导航点击选中事件的方法
2018/09/12 Javascript
关于vue.js中实现方法内某些代码延时执行
2019/11/14 Javascript
[05:59]2018DOTA2国际邀请赛寻真——只为胜利的Secret
2018/08/13 DOTA
基于python代码实现简易滤除数字的方法
2018/07/17 Python
Python函数的参数常见分类与用法实例详解
2019/03/30 Python
Mac中PyCharm配置Anaconda环境的方法
2020/03/04 Python
html5中如何将图片的绝对路径转换成文件对象
2018/01/11 HTML / CSS
日本土著品牌,综合型购物网站:Cecile
2016/08/23 全球购物
英国最大的海报商店:GB Posters
2018/03/20 全球购物
.net工程师笔试题
2012/06/09 面试题
销售顾问的岗位职责
2013/11/13 职场文书
节水口号标语
2014/06/19 职场文书
垃圾分类的活动方案
2014/08/15 职场文书
房屋授权无偿使用证明
2014/11/29 职场文书
2015年党员自我剖析材料
2014/12/17 职场文书
挂职锻炼个人总结
2015/03/05 职场文书
房地产项目合作意向书
2015/05/08 职场文书
因个人原因离职的辞职信范文
2015/05/12 职场文书