如何实现一个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 26 Python
决策树的python实现方法
Nov 18 Python
python3 与python2 异常处理的区别与联系
Jun 19 Python
浅谈Python浅拷贝、深拷贝及引用机制
Dec 15 Python
Python+matplotlib+numpy实现在不同平面的二维条形图
Jan 02 Python
Python 获得命令行参数的方法(推荐)
Jan 24 Python
浅谈Python黑帽子取代netcat
Feb 10 Python
Python基于opencv的图像压缩算法实例分析
May 03 Python
python numpy数组的索引和切片的操作方法
Oct 20 Python
Python3 chardet模块查看编码格式的例子
Aug 14 Python
python构建指数平滑预测模型示例
Nov 21 Python
python图片剪裁代码(图片按四个点坐标剪裁)
Mar 10 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
CodeIgniter整合Smarty的方法详解
2017/08/25 PHP
Laravel监听数据库访问,打印SQL的例子
2019/10/24 PHP
PHPExcel实现的读取多工作表操作示例
2020/04/14 PHP
AngularJS 让人爱不释手的八种功能
2016/03/23 Javascript
BOM系列第二篇之定时器requestAnimationFrame
2016/08/17 Javascript
jQuery模拟完美实现经典FLASH导航动画效果【附demo源码下载】
2016/11/09 Javascript
js中Number数字数值运算后值不对的解决方法
2017/02/28 Javascript
解决vue里碰到 $refs 的问题的方法
2017/07/13 Javascript
vue的基本用法与常见指令
2017/08/15 Javascript
详解vue 模拟后台数据(加载本地json文件)调试
2017/08/25 Javascript
jQuery中的类名选择器(.class)用法简单示例
2018/05/14 jQuery
用vue快速开发app的脚手架工具
2018/06/11 Javascript
clipboard.js在移动端复制失败的解决方法
2018/06/13 Javascript
Vuex持久化插件(vuex-persistedstate)解决刷新数据消失的问题
2019/04/16 Javascript
js刷新页面location.reload()用法详解
2019/12/09 Javascript
JavaScript遍历数组的方法代码实例
2020/01/14 Javascript
微信小程序开发打开另一个小程序的实现方法
2020/05/17 Javascript
JavaScript Image对象实现原理实例解析
2020/08/26 Javascript
vuejs实现下拉框菜单选择
2020/10/23 Javascript
javascript实现时钟动画
2020/12/03 Javascript
[01:56]林书豪DOTA2上海特级锦标赛励志短片
2016/03/05 DOTA
Python 除法小技巧
2008/09/06 Python
Python实现的下载8000首儿歌的代码分享
2014/11/21 Python
python清除指定目录内所有文件中script的方法
2015/06/30 Python
Python 专题一 函数的基础知识
2017/03/16 Python
对Python实现简单的API接口实例讲解
2018/12/10 Python
opencv python 图像轮廓/检测轮廓/绘制轮廓的方法
2019/07/03 Python
Python数组拼接np.concatenate实现过程
2020/04/18 Python
html5 Canvas画图教程(7)—canvas里画曲线之quadraticCurveTo方法
2013/01/09 HTML / CSS
加拿大国民体育购物网站:National Sports
2018/11/04 全球购物
自我鉴定总结
2014/03/24 职场文书
事业单位竞聘上岗实施方案
2014/03/28 职场文书
奥巴马竞选演讲稿
2014/05/15 职场文书
大气污染防治方案
2014/05/19 职场文书
中国在我心中演讲稿
2014/09/13 职场文书
大学生村官个人对照检查材料(群众路线)
2014/09/26 职场文书