Python功能点实现:函数级/代码块级计时器


Posted in Python onJanuary 02, 2019

工程中我们常常需要对某一个函数或者一块代码计时,从而监测系统关键位置的性能。计时方法是在代码块前后分别记录当前系统时间,然后两者相减得到代码块的耗时。最简单原始的实现类似:

from datetime import datetime
start = datetime.now()
# some code you want to measure
end = datetime.now()
print("Processing time for {} is: {} seconds".format('You Name It', elapse))

这种方式缺点明显:假如系统内有很多地方都需要计时,那么每个地方都需要插入这样的计时代码,首先是重复性工作很麻烦,其次这样会降低代码的可读性,干扰对业务逻辑的理解。本文将给出一些更好的实现,主要涉及的技术是装饰器(Decorator)和运行时上下文(runtime context)。

基于装饰器的函数级计时器

第一种计时器是比较常见的函数级计时器,通过装饰器完成,将原函数改装成拥有计时功能的新函数,使其可以完成运行原来函数和计时两件事。在使用时,只用在需要计时功能的函数代码前加上类似@timer的语法糖,这样每次调用原函数时,运行的将会是新函数。这样就大大减少了重复性劳动。

具体实现如下:

from datetime import datetime
def timer(func):
  '''Function Level Timer via Decorator'''
  def timed(*args, **kwargs):
    start = datetime.now()
    result = func(*args, **kwargs)
    end = datetime.now()
    elapse = (end - start).total_seconds()
    print("Processing time for {} is: {} seconds".format(func.__name__, elapse))
    return result
  return timed
@timer
def test_1(a):
  '''Function Level'''
  a *= 2
  return a
if __name__ == '__main__':
  print(test_1(1))

基于上下文的代码块级计时器

装饰器实现的计时器可以为函数添加计时功能,可以满足大部分情况的需要,但是假如我们想要更灵活一些,对任意一段连续的代码块做计时,怎样做?使用原始的插计时代码的方法显然不是我们想要的;也可以将代码块重构成一个函数,再在上面加装饰器,然而这就显得不够优雅。因此我做出了下面的实现。

首先了解上下文管理的概念。大致是说Python中允许创建一种叫上下文管理器(Context Manager)的对象,它可以管理一个代码块执行时的上下文信息。具体的方法是创建一个类,并为其实现object.__enter__和object.__exit__方法,前者在进入代码块时自动执行,后者在完成代码块执行时自动执行。

在使用时,通过with和as关键字,将__enter__的返回值绑定到某一个变量名,这个返回值里可以储存代码块运行过程中得到的一些信息,在这里就是运行时间啦。具体的实现是创建一个计时器类Timer,在enter时记录代码块运行的开始时间,exit时记录完成时间、计算并储存耗时到Timer实例中。在使用时,将with Timer() as t加到要计时的代码块前面,t.elapse中将会储存代码块耗时,可以任意使用。

在这个基础上,我们还可以做出一个装饰器timer_来实现基于上下文的函数级计时器。

具体实现如下:

class Timer(object):
  '''Code Block Level Timer via Context'''
  def __enter__(self):
    self.start = datetime.now()
    return self
  def __exit__(self, *args):
    self.end = datetime.now()
    self.elapse = (self.end - self.start).total_seconds()
def timer_(func):
  '''Function Level Timer via Context & with Statement'''
  def timed(*args, **kw):
    with Timer() as t:
      result = func(*args, **kw)
    print("Processing time for {} is: {} seconds".format(func.__name__, t.elapse))
    return result
  return timed
def test_2(a):
  '''Code Block Level'''
  with Timer() as t:
    a *= 2
  print("Processing time for {} is: {} seconds".format('You Name It', t.elapse))
  return a
@timer_
def test_3(a):
  '''Function Level'''
  a *= 2
  return a
if __name__ == '__main__':
  print(test_2(2))
  print(test_3(3))

更灵活的实现

更优雅地,我们还可以使用contextlib自带的ContextDecorator,参考官方示例,做出既可以with又可以作为装饰器的计时器timer_elegant:

from datetime import datetime
from contextlib import ContextDecorator
class timer_elegant(ContextDecorator):
  '''Elegant Timer via ContextDecorator'''
  def __init__(self, name):
    self.name = name
  def __enter__(self):
    self.start = datetime.now()
  def __exit__(self, *args):
    self.end = datetime.now()
    self.elapse = (self.end - self.start).total_seconds()
    print("Processing time for {} is: {} seconds".format(self.name, self.elapse))
@timer_elegant('test_4')
def test_4(a):
  a *= 2
  return a
def test_5(a):
  a *= 2
  return a
if __name__ == '__main__':
  print(test_4(4))
 
  with timer_elegant('test 5'):
    result_5 = test_5(5)
  print(result_5)

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。如果你想了解更多相关内容请查看下面相关链接

Python 相关文章推荐
200 行python 代码实现 2048 游戏
Jan 12 Python
Python cookbook(数据结构与算法)在字典中将键映射到多个值上的方法
Feb 18 Python
python控制windows剪贴板,向剪贴板中写入图片的实例
May 31 Python
python3写的简单本地文件上传服务器实例
Jun 04 Python
python广度优先搜索得到两点间最短路径
Jan 17 Python
利用Pandas和Numpy按时间戳将数据以Groupby方式分组
Jul 22 Python
python设计tcp数据包协议类的例子
Jul 23 Python
使用jupyter Nodebook查看函数或方法的参数以及使用情况
Apr 14 Python
DataFrame 数据合并实现(merge,join,concat)
Jun 14 Python
Pytorch实现将模型的所有参数的梯度清0
Jun 24 Python
python的dict判断key是否存在的方法
Dec 09 Python
单身狗福利?Python爬取某婚恋网征婚数据
Jun 03 Python
详解如何在Apache中运行Python WSGI应用
Jan 02 #Python
漂亮的Django Markdown富文本app插件的实现
Jan 02 #Python
对Python发送带header的http请求方法详解
Jan 02 #Python
Django渲染Markdown文章目录的方法示例
Jan 02 #Python
使用python 打开文件并做匹配处理的实例
Jan 02 #Python
对Xpath 获取子标签下所有文本的方法详解
Jan 02 #Python
python之验证码生成(gvcode与captcha)
Jan 02 #Python
You might like
PHP4实际应用经验篇(2)
2006/10/09 PHP
从一个不错的留言本弄的mysql数据库操作类
2007/09/02 PHP
php 求质素(素数) 的实现代码
2011/04/12 PHP
php往mysql中批量插入数据实例教程
2018/12/12 PHP
Yii框架组件的事件机制原理与用法分析
2020/04/07 PHP
jQuery的强大选择器小结
2009/12/27 Javascript
js实现日期级联效果
2014/01/23 Javascript
JavaScript DOM节点添加示例
2014/07/16 Javascript
js实现的奥运倒计时时钟效果代码
2015/12/09 Javascript
Vue.js组件tree实现无限级树形菜单
2016/12/02 Javascript
Vue集成Iframe页面的方法示例
2017/12/12 Javascript
JS引用传递与值传递的区别与用法分析
2018/06/01 Javascript
angularJs中ng-model-options设置数据同步的方法
2018/09/30 Javascript
vue 基于element-ui 分页组件封装的实例代码
2018/12/10 Javascript
vue-router实现嵌套路由的讲解
2019/01/19 Javascript
详解ES6中的Map与Set集合
2019/03/22 Javascript
详细讲解如何创建, 发布自己的 Vue UI 组件库
2019/05/29 Javascript
vue 框架下自定义滚动条(easyscroll)实现方法
2019/08/29 Javascript
[01:05:24]Ti4 冒泡赛第二天 iG vs NEWBEE 3
2014/07/15 DOTA
Python中map,reduce,filter和sorted函数的使用方法
2015/08/17 Python
使用Kivy将python程序打包为apk文件
2017/07/29 Python
wxpython实现图书管理系统
2018/03/12 Python
python文件写入write()的操作
2019/05/14 Python
详解在Python中以绝对路径或者相对路径导入文件的方法
2019/08/30 Python
Python openpyxl读取单元格字体颜色过程解析
2019/09/03 Python
日本钓鱼渔具和户外用品网上商店:naturum
2016/08/07 全球购物
Boda Skins皮衣官网:奢侈皮夹克,全球配送
2016/12/15 全球购物
西班牙灯具网上商店:Lampara.es
2018/06/05 全球购物
CAD制图设计师自荐信
2014/01/29 职场文书
十八届三中全会感言
2014/03/10 职场文书
报考公务员诚信承诺书
2014/08/29 职场文书
2014党员民主评议个人思想剖析发言
2014/09/19 职场文书
杜甫草堂导游词
2015/02/03 职场文书
2015年留守儿童工作总结
2015/05/22 职场文书
辩论赛开场白大全(主持人+辩手)
2015/05/29 职场文书
2016年父亲节寄语
2015/12/04 职场文书