如何让 Python timeit 模块不重复循环中的最后一次迭代

How to get Python timeit module to not repeat the last iteration within a loop

我正在使用 timeit 进行一些负载测试。我正在遍历一个列表。在我尝试过的一切中,timeit 重复列表中的最后一个值 3 次。我知道重复默认为 3。我试过不使用重复。我试过使用重复,但将重复设置为 0。我想要的是重复 0 次,或者选择正确参数而不是重复最后一个参数 3 次的重复。我将向您展示我尝试过的内容,然后是预期结果和实际结果。

我的模块名为 z_sandbox.py,我在模块中通过在 VS Code 中执行来调用它。我没有使用命令行。

我尝试了三种不同的选择:

选项 #1:timeit.Timer,未指定重复项。

import timeit
params = ["param1", "param2", "param3"]
print("*****START*****")
for param in params:  
    print('STARTING: %s ' % (param))   
    timeit.Timer(
        stmt="print('%s ' % (z_sandbox.param))",
        setup="import z_sandbox"
    ).timeit(number=3)
print("*****DONE*****")

预期结果:

在上面我没有使用重复,所以我希望没有重复,并且每个语句恰好执行 3 次,总共执行 9 次。

预期:

*****START*****
STARTING: param1
param1
param1
param1
STARTING: param2
param2
param2
param2
STARTING: param3
param3
param3
param3
*****DONE*****

实际:

*****START*****
STARTING: param1
*****START*****
STARTING: param1
param1
param1
param1
STARTING: param2
param2
param2
param2
STARTING: param3
param3
param3
param3
*****DONE*****
param3
param3
param3
STARTING: param2
param3
param3
param3
STARTING: param3
param3
param3
param3
*****DONE*****

问题:为什么 "STARTING: param1" 在顶部打印两次?为什么最后9次执行都是param3,而不是每个参数执行3次?为什么在重复中有 "STARTING: param2" 但实际执行的是 param3?我如何获得预期的结果,即不重复?

选项 #2:timeit.repeat,指定重复 1 次。

timeit.repeat(
    stmt="print('%s ' % (z_sandbox.param))",
    setup="import z_sandbox",
    repeat=1,
    number=3
)

以上产生与选项 #1 相同的结果。

选项 #3:timeit.repeat,指定重复 0 次。

timeit.repeat(
    stmt="print('%s ' % (z_sandbox.param))",
    setup="import z_sandbox",
    repeat=0,
    number=3
)

上面什么也没有产生。

以上各项的变化

我还尝试将输出打印到文件,而不是屏幕。输出没有区别。

如何获得预期的结果,即不重复?

您可以将可调用对象作为 stmt 传递给 Timer

timeit.Timer(stmt=lambda: print('%s ' % (param,))).timeit(number=3)

您的代码的问题是它没有主要的导入保护来防止第二次导入模块时出现主要代码。关于主要模块的事情是它们可以被加载两次。一次作为 __main__,一次在它们的模块名称下。

您的代码可以通过以下方式修复:

import timeit
params = ["param1", "param2", "param3"]
if __name__=="__main__":
    print("*****START*****")
    for idx, param in enumerate(params): 
        print('STARTING: %s ' % (param,)) 
        timeit.Timer(stmt="print('%%s ' %% (z_sandbox.params[%r]))" % (idx,), setup="import z_sandbox" ).timeit(number=3)
    print("*****DONE*****")