将“with”语句分解为各种函数

时间:2017-10-17 12:08:34

标签: python python-3.x contextmanager

我写了一个通用框架,帮助我对代码关键部分进行基准测试。

以下是对框架的解释,最后是我面临的问题以及我对解决方案的一些想法。

基本上,我正在寻找更优雅的解决方案

假设我有一个执行此操作的函数(伪代码):

#Pseudo Code - Don't expect it to run

def foo():
   do_begin()
   do_critical()
   some_value = do_end()
   return some_value

我想在循环中多次运行“do_critical”部分并测量时间但仍然得到返回值。

所以,我写了BenchMarker类,它的api是这样的:

#Pseudo Code - Don't expect it to run

bm = BenchMarker(first=do_begin, critical=do_critical, end=do_end)
bm.start_benchmarking()
returned_value = bm.returned_value
benchmark_result = bm.time

本Benckmarker内部执行以下操作:

#Pseudo Code - Don't expect it to run

class BenchMarker:    
  def __init__(self):
     .....

  def start_benchmarking(self):
    first()
    t0 = take_time
    for i in range(n_loops):
      critical()
    t1 = take_time
    self.time = (t1-t0)/n_loops

    value = end()
    self.returned_value = value

重要的是要提到我也能够在第一个,关键函数和结束函数之间传递上下文,但为了简单起见我省略了它,因为这不是我问题的要点。

在以下用例之前,此框架就像魅力一样:

我有以下代码

#Pseudo Code - Don't expect it to run    

def bar():
  do_begin()

  with some_context_manager() as ctx:
    do_critical()

  some_value = do_end()
  return some_value

现在,经过这个漫长的介绍(对不起......),我正在回答真正的问题。

我不想在时间测量循环中运行“with statement”,但关键代码需要上下文管理器。

所以我基本上想要的就是以下分解吧:

first ->  do_begin() + "what happens in the with before the with body"
critical -> do_critical()
end -> "what happens after the with body" + do_end()

我想到的两个解决方案(但我不喜欢):

解决方案1 ​​ 模仿引擎盖下的内容

  • 在first()结尾处创建上下文管理器对象+运行它输入()函数
  • 在结束()的开头,调用上下文管理器退出()函数

解决方案2 框架增强处理CM

在框架中添加“上下文工作模式”(标志,无论......),“start_benchmarking”流程将如下所示:

#Pseudo Code - Don't expect it to run 

def start_benchmarking(self):
  first() #including instantiating the context manager
  ctx = get_the_context_manager_created_in_first()      

  with ctx ...:

    t0 = take_time
    for i in range(n_loops):
      critical()
    t1 = take_time

  self.time = (t1-t0)/n_loops      
  value = end()
  self.returned_value = value

任何其他更优雅的解决方案?

1 个答案:

答案 0 :(得分:0)

这是过于复杂的方式。而且我无法弄清楚为什么你真的想要这样做,但假设你有理由,只需创建一个能为你做时机的函数:

def run_func_n_times(n_times, func, *args, **kwargs):
    start = time.time()
    for _ in range(n_times):
        res = func(*args, **kwargs)
    return res, (time.time() - start) / n_times

不需要一个类,只需一个简单的函数:

def example():
    do_begin()
    print('look, i am here')
    with ctx() as blah:
        res, timed = run_func_n_times(27, f, foo, bar)
    do_end()