如何实现一个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文件去除注释的方法
May 25 Python
Python 'takes exactly 1 argument (2 given)' Python error
Dec 13 Python
python3读取MySQL-Front的MYSQL密码
May 03 Python
django输出html内容的实例
May 27 Python
pycharm下查看python的变量类型和变量内容的方法
Jun 26 Python
不到20行代码用Python做一个智能聊天机器人
Apr 19 Python
eclipse创建python项目步骤详解
May 10 Python
解决django FileFIELD的编码问题
Mar 30 Python
在PyTorch中使用标签平滑正则化的问题
Apr 03 Python
PyQt5 控件字体样式等设置的实现
May 13 Python
Python定义一个函数的方法
Jun 15 Python
Python+Kepler.gl实现时间轮播地图过程解析
Jul 20 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 iconv函数的使用详解
2013/06/09 PHP
使用PHP求两个文件的相对路径
2013/06/20 PHP
PHP实现加强版加密解密类实例
2015/07/29 PHP
Thinkphp框架开发移动端接口(1)
2016/08/18 PHP
在 Laravel 中动态隐藏 API 字段的方法
2019/10/25 PHP
PHP设计模式(一)工厂模式Factory实例详解【创建型】
2020/05/02 PHP
javascript之锁定表格栏位
2007/06/29 Javascript
IE innerHTML,outerHTML所引起的问题
2009/06/04 Javascript
javascript禁制后退键(Backspace)实例代码
2013/11/15 Javascript
javascript实现多级联动下拉菜单的方法
2015/02/06 Javascript
学习JavaScript设计模式之观察者模式
2020/04/22 Javascript
Vue2 使用 Echarts 创建图表实例代码
2017/05/18 Javascript
基于ES6 Array.of的用法(实例讲解)
2017/09/05 Javascript
JS设计模式之数据访问对象模式的实例讲解
2017/09/30 Javascript
jQuery实现判断上传图片类型和大小的方法示例
2018/04/11 jQuery
详解基于Vue cli生成的Vue项目的webpack4升级
2018/06/19 Javascript
npm配置国内镜像资源+淘宝镜像的方法
2018/09/07 Javascript
Vue使用zTree插件封装树组件操作示例
2019/04/25 Javascript
JS中比Switch...Case更优雅的多条件判断写法
2019/09/05 Javascript
webpack 处理CSS资源的实现
2019/09/27 Javascript
vue项目中使用多选框的实例代码
2020/07/22 Javascript
[02:20]DOTA2中文配音宣传片
2013/05/22 DOTA
[47:26]完美世界DOTA2联赛 LBZS vs Forest 第二场 11.07
2020/11/09 DOTA
几个提升Python运行效率的方法之间的对比
2015/04/03 Python
使用python实现ANN
2017/12/20 Python
解决pycharm 安装numpy失败的问题
2019/12/05 Python
HTML5的Video标签有部分MP4无法播放的问题解析(多图)
2017/08/18 HTML / CSS
2014年大学生四年规划书范文
2014/04/03 职场文书
2014年民主评议党员个人总结
2014/09/24 职场文书
师德先进个人材料
2014/12/20 职场文书
优秀大学生事迹材料
2014/12/24 职场文书
汽车销售助理岗位职责
2015/04/14 职场文书
通用员工手册范本
2015/05/14 职场文书
素质拓展训练感想
2015/08/07 职场文书
css3实现背景图片颜色修改的多种方式
2021/04/13 HTML / CSS
Python学习之迭代器详解
2022/04/01 Python