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

yipeiwu_com7年前Python基础

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

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设计】的支持。如果你想了解更多相关内容请查看下面相关链接

相关文章

Django中对通过测试的用户进行限制访问的方法

限制访问可以基于某种权限,某些检查或者为login视图提供不同的位置,这些实现方式大致相同。 一般的方法是直接在视图的 request.user 上运行检查。 例如,下面视图确认用户登...

Python实现html转换为pdf报告(生成pdf报告)功能示例

本文实例讲述了Python实现html转换为pdf报告(生成pdf报告)功能。分享给大家供大家参考,具体如下: 1、先说下html转换为pdf:其实支持直接生成,有三个函数pdfkit....

Python实现自动上京东抢手机

本文实例为大家分享了Python自动上京东抢手机的具体代码,供大家参考,具体内容如下 上次抢荣耀V9,被京东给恶心到了,所以就写了个简单的Python来自动抢V9。虽然用的是比较蠢的方法...

Python字典底层实现原理详解

在Python中,字典是通过散列表或说哈希表实现的。字典也被称为关联数组,还称为哈希数组等。也就是说,字典也是一个数组,但数组的索引是键经过哈希函数处理后得到的散列值。哈希函数的目的是使...

python实现高斯(Gauss)迭代法的例子

我就废话不多说了,直接上代码大家一起看吧! #Gauss迭代法 输入系数矩阵mx、值矩阵mr、迭代次数n(以list模拟矩阵 行优先) def Gauss(mx,mr,n=100):...