如何实现一个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爬虫技巧汇总
Sep 28 Python
解决Mac下首次安装pycharm无project interpreter的问题
Oct 29 Python
python实现对指定字符串补足固定长度倍数截断输出的方法
Nov 15 Python
使用python list 查找所有匹配元素的位置实例
Jun 11 Python
python写程序统计词频的方法
Jul 29 Python
Python JSON编解码方式原理详解
Jan 20 Python
Python Numpy,mask图像的生成详解
Feb 19 Python
Python调用OpenCV实现图像平滑代码实例
Jun 19 Python
matplotlib 画双轴子图无法显示x轴的解决方法
Jul 27 Python
Python同时迭代多个序列的方法
Jul 28 Python
scrapy结合selenium解析动态页面的实现
Sep 28 Python
python3定位并识别图片验证码实现自动登录功能
Jan 29 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
利用js调用后台php进行数据处理原码
2006/10/09 PHP
php db类库进行数据库操作
2009/03/19 PHP
PHP错误抑制符(@)导致引用传参失败Bug的分析
2011/05/02 PHP
解析关于java,php以及html的所有文件编码与乱码的处理方法汇总
2013/06/24 PHP
解析wamp5下虚拟机配置文档
2013/06/27 PHP
PHP中比较时间大小实例
2014/08/21 PHP
php中current、next与reset函数用法实例
2014/11/17 PHP
php采集内容中带有图片地址的远程图片并保存的方法
2015/01/03 PHP
PHP使用JSON和将json还原成数组
2015/02/12 PHP
PHP实现字符串的全排列详解
2019/04/24 PHP
Javascript动态绑定事件的简单实现代码
2010/12/25 Javascript
jquery attr 设定src中含有&(宏)符号问题的解决方法
2011/07/26 Javascript
简单实例处理url特殊符号&处理(2种方法)
2013/04/02 Javascript
jquery可见性过滤选择器使用示例
2013/06/24 Javascript
javascript设计模式--策略模式之输入验证
2015/11/27 Javascript
详解JavaScript函数
2015/12/01 Javascript
jQuery使用$.ajax进行即时验证实例详解
2015/12/11 Javascript
JavaScript计时器用法分析【setTimeout和clearTimeout】
2017/01/18 Javascript
JS排序之选择排序详解
2017/04/08 Javascript
jquery.uploadView 实现图片预览上传功能
2017/08/10 jQuery
jQuery中的for循环var与let的区别
2018/04/21 jQuery
微信小程序select下拉框实现源码
2019/11/08 Javascript
[50:59]2018DOTA2亚洲邀请赛 4.7 总决赛 LGD vs Mineski第四场
2018/04/10 DOTA
[54:28]EG vs OG 2019国际邀请赛小组赛 BO2 第一场 8.16
2019/08/18 DOTA
回调函数的意义以及python实现实例
2017/06/20 Python
简单了解OpenCV是个什么东西
2017/11/10 Python
Python常用数据类型之间的转换总结
2019/09/06 Python
python日志模块logbook使用方法
2019/09/19 Python
django filter过滤器实现显示某个类型指定字段不同值方式
2020/07/16 Python
基于Python爬取京东双十一商品价格曲线
2020/10/23 Python
如何使用Pytorch搭建模型
2020/10/26 Python
阿迪达斯越南官网:adidas越南
2020/07/19 全球购物
2015年医务人员医德医风自我评价
2015/03/03 职场文书
2015年学校办公室主任工作总结
2015/07/20 职场文书
初中班主任培训心得体会
2016/01/07 职场文书
GO中sync包自由控制并发示例详解
2022/08/05 Golang