首页 > 解决方案 > 是否有一种 Pythonic 的方式来跳过 for 循环中的 if 语句以使我的代码运行得更快?

问题描述

我正在用 Python 编写一个脚本,该脚本本质上是掷骰子并检查掷骰子是否超过数字x。我想重复这个过程n次数并获得骰子超过数字的概率x。例如

Count = 0
for _ in itertools.repeat(None, Iterations):
    x = 3
    die_roll = rnd.randint(1,6)
    if die_roll > x:
        Count += 1
Probability_of_exceed = Count / Iterations

我想根据用户输入同时修改骰子和 x。此用户输入将选择不同的例程来修改脚本,例如"Andy's_Routine"可能更改x4. 目前,我在 for 循环中使用 if 语句来检查哪些例程处于活动状态,然后应用它们,例如

Count = 0
for _ in itertools.repeat(None, Iterations):
    x = 3

    if "Andy's_Routine" in Active_Routines:
        x = 4

    die_roll = rnd.randint(1,6)
    if "Bill's_Routine" in Active_Routines:
        die_roll += 1 
    if "Chloe's_Routine" in Active_Routines:
        # do something
        pass

    if "Person_10^5's_Routine" in Active_Routines:
        # do something else
        pass

    if die_roll > x:
        Count += 1
Probability_of_exceed = Count / Iterations

在实践中,例程并不是那么简单,以至于它们可以被概括,例如,它们可能会添加额外的输出。这些例程可以同时执行。问题是可能有数千个不同的例程,因此每个循环将花费大部分时间检查 if 语句,从而减慢程序的速度。

有没有更好的方法来构造代码来检查哪些例程只使用一次,然后以某种方式修改迭代?

标签: pythonloopsif-statementoptimizationiteration

解决方案


你在这里问了两件事——你希望你的代码更加 Pythonic,并且你希望它运行得更快。

第一个更容易回答:制作Active_Routines一个函数列表而不是字符串列表,然后从列表中调用函数。由于这些函数可能需要更改本地状态(xdie_roll),您需要将状态作为参数传递给它们,并让它们返回一个新状态。重构可能如下所示:

def Andy(x, die_roll):
    return (4, die_roll)

def Bill(x, die_roll):
    return (x, die_roll + 1)

def Chloe(x, die_roll):
    # do something
    return (x, die_roll)

Active_Routines = [Andy, Bill, Chloe]

Count = 0
for i in range(Iterations):
    x = 3
    die_roll = rnd.randint(1,6)

    for routine in Active_Routines:
        x, die_roll = routine(x, die_roll)

    if die_roll > x:
        Count += 1

Probability_of_exceed = Count / Iterations

第二个更难回答。这种重构现在进行了大量的函数调用,而不是检查if条件;所以可能会有更少的错过分支预测,但更多的函数调用开销。您必须对其进行基准测试(例如使用timeit 库)才能确定。但是,至少这段代码应该更容易维护。


推荐阅读