如何实现一个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中使用urllib2伪造HTTP报头的2个方法
Jul 07 Python
python常用函数详解
Sep 13 Python
Python 正则表达式实现计算器功能
Apr 29 Python
Python中定时任务框架APScheduler的快速入门指南
Jul 06 Python
Python 异常处理的实例详解
Sep 11 Python
python中copy()与deepcopy()的区别小结
Aug 03 Python
Python设计模式之工厂方法模式实例详解
Jan 18 Python
Django框架实现的分页demo示例
May 25 Python
Jupyter notebook如何修改平台字体
May 13 Python
Django使用rest_framework写出API
May 21 Python
Tensorflow中批量读取数据的案列分析及TFRecord文件的打包与读取
Jun 30 Python
python中lower函数实现方法及用法讲解
Dec 23 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
探讨file_get_contents与curl效率及稳定性的分析
2013/06/06 PHP
php unset全局变量运用问题的深入解析
2013/06/17 PHP
PHP生成二维码的两个方法和实例
2014/07/01 PHP
PHP依赖注入(DI)和控制反转(IoC)详解
2017/06/12 PHP
如何在PHP中读写文件
2020/09/07 PHP
jQuery 标题的自动翻转实现代码
2009/10/14 Javascript
Javascript实现滑块滑动改变值的实现代码
2013/04/12 Javascript
Nodejs中调用系统命令、Shell脚本和Python脚本的方法和实例
2015/01/01 NodeJs
使用JavaScript开发IE浏览器本地插件实例
2015/02/18 Javascript
详解AngularJS Filter(过滤器)用法
2015/12/28 Javascript
基于jquery实现瀑布流布局
2020/06/28 Javascript
基于Vuejs和Element的注册插件的编写方法
2017/07/03 Javascript
vue+vuex+axios+echarts画一个动态更新的中国地图的方法
2017/12/19 Javascript
vue2 全局变量的设置方法
2018/03/09 Javascript
ES10 特性的完整指南小结
2019/03/04 Javascript
vue cli4.0项目引入typescript的方法
2020/07/17 Javascript
解决vue+webpack项目接口跨域出现的问题
2020/08/10 Javascript
[01:13]2015国际邀请赛线下观战现场
2015/08/08 DOTA
python 从远程服务器下载东西的代码
2013/02/10 Python
使用python调用浏览器并打开一个网址的例子
2014/06/05 Python
利用Python演示数型数据结构的教程
2015/04/03 Python
python获取本机mac地址和ip地址的方法
2015/04/29 Python
Python实现连接两个无规则列表后删除重复元素并升序排序的方法
2018/02/05 Python
Flask框架web开发之零基础入门
2018/12/10 Python
Python实现繁?转为简体的方法示例
2018/12/18 Python
Python 用三行代码提取PDF表格数据
2019/10/13 Python
Python qrcode 生成一个二维码的实例详解
2020/02/12 Python
django使用F方法更新一个对象多个对象字段的实现
2020/03/28 Python
用css3实现转换过渡和动画效果
2020/03/13 HTML / CSS
Java的for语句中break, continue和return的区别
2013/12/19 面试题
电子商务专业学生职业生涯规划
2014/03/07 职场文书
学校与家长安全责任书
2014/07/23 职场文书
2014年司法所工作总结
2014/11/22 职场文书
2014年卫生保健工作总结
2014/12/08 职场文书
超详细Python解释器新手安装教程
2021/05/10 Python
Python爬虫之用Xpath获取关键标签实现自动评论盖楼抽奖(二)
2021/06/07 Python