我们假设我们希望使用timeit进行一些不同输入的性能测试。
显而易见的非DRY方式是这样的:
import timeit
# define functions to test
def some_list_operation_A(lst):
...
def some_list_operation_B(lst):
...
# create different lists (different input) to test the functions with
...
inputs = [lsta, lstb, lstc, ...]
# measure performance with first function
num = 10
t_lsta = timeit.timeit("some_list_operation_A(lsta)",
setup="from __main__ import some_list_operation_A, lsta",
number=num)
t_lstb = timeit.timeit("some_list_operation_A(lstb)",
setup="from __main__ import some_list_operation_A, lstb",
number=num)
t_lstc = timeit.timeit("some_list_operation_A(lstc)",
setup="from __main__ import some_list_operation_A, lstc",
number=num)
...
# print results & do some comparison stuff
for res in [t_lsta, t_lstb, t_lstc, ...]:
print("{:.4f}s".format(res))
...
# do this ALL OVER AGAIN for 'some_list_operation_B'
...
# print new results
# do this ALL OVER AGAIN for 'some_list_operation_C'
# ...I guess you'll got the point
...
我认为应该非常清楚,这对于衡量不同输入的不同功能的性能是一种非常难看的方式。
我目前的做法是这样的:
...
inputs = dict()
inputs["lsta"] = lsta
inputs["lstb"] = lstb
inputs["lstc"] = lstc
for f in ["some_list_operation_A", "some_list_operation_B", ...]:
r = dict() # results
for key, val in inputs.iteritems():
r[key] = timeit.timeit("{}(inputs[{}])".format(f, key),
setup="from __main__ import {}, inputs".format(f),
number=num
# evaluate results 'r' for function 'f' here
# (includes a comparison of the results -
# that's why I save them in 'r')
...
# loop moves on to next function 'f'
基本上,我在这里使用.format
来插入函数名称并插入正确的数据inputs[key]
。在.format
填写所有{}
后,结果是stmt
一个正确的timeit
字符串。
虽然这比明显的非DRY解决方案要短得多,但它的可读性也更低,更像黑客,不是吗?
对于此类问题,什么是合适的DRY解决方案?
我还想过用装饰器来简单地计算功能(这会很整洁?!) - 但我没有成功:装饰者不应该只打印结果。在我的# evaluate results 'r'
步骤中,我不仅打印结果,而且还在比较它们:比如计算相对差异和内容。因此,我需要装饰器返回一些东西,以便比较每次运行的结果......
有人可以向我提出正确的方向,以获得干净的pythonic解决方案吗?我希望有更多漂亮/意识形态的代码......尤其是:更短代码!