2014-10-05 65 views
3

我很难总结这个问题,所以我将描述我想要做的事情:如何逐行停止函数的执行?

我正在为某个产品写一个测试解决方案,可以说是微波炉。目的是在使用微波炉的同时测量各种资源。为此我编写了一个名为measure()的上下文管理器。

使用微波API我写的模拟微波的基本用例的功能,并与做测量的全部功能,装饰它:

def test_function(fn): 
    def wrapper(*args, **kwargs): 
     with measure(): 
      fn(*args, **kwargs) 

    return wrapper 

@test_function 
def prepare_food(): 
    microwave = Microwave() 
    microwave.open_door() 
    microwave.insert_food() 
    microwave.close_door() 
    microwave.turn_on(seconds = 60) 

prepare_food() 

当然微波炉仅仅是一个例子我有很多这种“微波炉”。

经过测试和测量我的团队的几天决定他们想分别评估每一个动作,这意味着我的测试功能现在这个样子:

def test_prepare_food(): 
    microwave = Microwave() 
    actions = { 
      microwave.open_door : [], 
      microwave.insert_food : [], 
      microwave.close_door() : [], 
      microwave.turn_on : [60] 
      } 
    for (action, args) in actions.items(): 
      with measure(): 
       action(*args) 

test_prepare_food的问题是,现在每个prepare_food函数,我需要添加另一个test_*函数(并且我有很多)。

我正在寻找一种让我的prepare_food函数保持一致的优雅方式,并且用另一个函数包装它,所以我仍然可以获得与test_prepare_food中相同的功能。

编辑: 我们的目标是,将不依赖于prepare_food()一实施,使prepare_food()变化将不需要额外的变化的解决方案。此外,该解决方案不应影响prepare_food未使用的方法。

换句话说,我希望能够“步入”prepare_food并能够在每行之前和之后执行代码。这类似于调试时完成的工作,但我找不到任何相似的东西。

任何想法?

谢谢!

+0

只是在早期得到了这一点的呢? (因为这将是一个分析器的工作)。您还需要跟踪一些需要自定义代码进行测量的其他资源? – 2014-10-05 13:33:26

+0

@LukasGraf - 没错,我正在测量其他资源,像微波炉产生的热量等等。 – NStiner 2014-10-05 14:20:57

回答

2

您可以使用measure方法修饰Microwave类的每个实例方法。这可以通过Microwave类的类装饰器完成。对于这个例子,我只是通过一种方法修改Microwave类。完成这项工作的方法是wrapwrap_method

import inspect 

class measure(object): 
    def __enter__(self): 
     print "Enter measure." 
    def __exit__(self, *args): 
     print "Exit measure." 

class Microwave(object): 
    def f(self, x): 
     print "f: %s" % x 
    def g(self, x): 
     print "g: %s" % x 

def wrap_method(method): 
    def wrapper(*args, **kwargs): 
     with measure(): 
      method(*args, **kwargs) 
    return wrapper 

def wrap(cls): 
    for name, method in inspect.getmembers(cls, predicate=inspect.ismethod): 
     setattr(cls, name, wrap_method(method)) 

wrap(Microwave) 
m = Microwave() 
m.f(1) 
m.g(2) 

输出是:你不只是在寻找衡量*执行时间*每行,正确的是:

Enter measure. 
f: 1 
Exit measure. 
Enter measure. 
g: 2 
Exit measure. 
+0

使用'inspect.getmembers'时的+1,但它不完全是我要找的 - 1)它取决于“准备食物”的实施; 2)它会改变所有微波炉的方法 - 包括那些不是我直接使用的方法。我编辑了这个问题来提到这个要求。 – NStiner 2014-10-06 05:46:20