首页 > 解决方案 > Repeatedly check conditions inside loop or check up front but have two loops?

问题描述

I have implemented a python function in 2 different ways, as shown below:

1st:

def  foo(varA, varB):
    if not (varA or varB):
        return False

    for test1 in test2:
        if varA:
            # Perform Action A
        if varB:
            # Perform Action B

    return True

2nd:

def foo(varA, varB):
    if not (varA or varB):
        return False

    if varA:
        for test1 in test2:
            # Perform Action A

    if varB:
        for test1 in test2:
            # Perform Action B

    return True

I want to know which method will take less time in execution.

标签: pythonpython-3.x

解决方案


这取决于.

这里没有确定的答案。这取决于迭代的成本、迭代的元素数量以及测试布尔值的成本。如果bool(varA)orbool(varB)成本(实现速度慢),那么您希望避免该成本并只循环test2两次。

但是如果迭代test2很慢(it = iter(test2)然后重复调用next(it)很慢),那么你会想要避免迭代两次。

最后,这里有两个 O(N) 线性算法。哪个更快完全取决于固定成本。您必须对代码进行计时才能知道选择哪一个。确保在不同的场景下多次运行测试,因为两者之间的正态分布是什么很重要,两者之间的正确分布bool(varA)频率 bool(varB)是多少?如果其中一个很少是正确的,那可能会对整体执行成本产生影响。

如果我们假设varAvarB是同一类型的对象,并且在测试它们的布尔真值的成本上没有差异,那么将其转换为公式,则两个选项的成本可以表示为:

cost_iteration * length * (2 * cost_test)

(2 * cost_test) + ((1 + probability_of_both_true) * cost_iteration * length)

其中cost_iteration是使迭代器前进一步的成本,test2需要length迭代的次数,以及确定orcost_test的布尔值的成本。varAvarB

请注意,我忽略了test2不是可迭代而是一次性迭代器的可能性。如果test2是一个迭代器,那么您不能多次循环它,因此您别无选择。

从上面的公式可以看出,即使使用标准的 Python 类型, and 没有自定义__bool____len__实现varAandvarB没有自定义__iter____getitem__实现test2wheretest2不是打开的文件对象(I/O 很),它仍然取决于两个值都为真的频率。

timeit使用模块的一些简单的计时测试很容易看到这一点,并且test2 = range(100)

>>> import timeit
>>> def option1(a, b):
...     if not (a or b): return False
...     for _ in test2:
...         if a: pass
...         if b: pass
...
>>> def option2(a, b):
...     if not (a or b): return False
...     if a:
...         for _ in test2: pass
...     if b:
...         for _ in test2: pass
...
>>> test2 = range(100)

两个变量都为真:

>>> timeit.timeit("t(True, True)", "from __main__ import option1 as t")
1.917803047000234
>>> timeit.timeit("t(True, True)", "from __main__ import option2 as t")
2.0743740369998704

只有一个变量为真:

>>> timeit.timeit("t(True, False)", "from __main__ import option1 as t")
1.7149272380002003
>>> timeit.timeit("t(True, False)", "from __main__ import option2 as t")
1.095426841000517

timeit.timeit()默认情况下重新运行测试 100 万次,因此上述时间以每次执行的微秒为单位

如果两者varAvarB主要正确的,那么第一个选项会稍微快一点。但是,如果只有其中一个是正确的更为常见,那么您需要第二种选择,因为它不必经常测试,因此以显着优势获胜。

如果要迭代的元素更多,时间可能会有所不同test2,因此您选择哪一个还必须考虑到您的典型迭代计数将是多少。


推荐阅读