为什么“全部”实现比编写for循环要慢

cub*_*bei 7 python

我得到一个列表,想知道所有元素是否相同。对于确实具有相同数量的元素数量很高的列表,将其转换为a set的速度很快,但通过提前退出列表遍历的效果更好:

def are_all_identical_iterate(dataset):
    first = dataset[0]
    for data in dataset:
        if data != first:
            return False
    return True

# versus

def are_all_identical_all(dataset):
    return all(data == dataset[0] for data in dataset)
# or
def are_all_identical_all2(dataset):
    return all(data == dataset[0] for data in iter(dataset))
# or
def are_all_identical_all3(dataset):
    iterator = iter(dataset)
    first = next(iterator)
    return all(first == rest for rest in iterator)

NUM_ELEMENTS = 50000
testDataset = [1337] * NUM_ELEMENTS # all identical

from timeit import timeit
print(timeit("are_all_identical_iterate(testDataset)", setup="from __main__ import are_all_identical_iterate, testDataset", number=1000))
print(timeit("are_all_identical_all(testDataset)", setup="from __main__ import are_all_identical_all, testDataset", number=1000))

Run Code Online (Sandbox Code Playgroud)

我的结果:0.94秒,3.09秒,3.27秒,2.61秒

for循环所花费的时间少于all函数的时间(3x)。该all功能应该是相同的实现

到底是怎么回事?我想知道为什么循环如此之快,以及为什么最后三个实现之间存在差异。最后一个实现应该少比较,因为迭代器删除了第一个元素,但这不会产生这种影响。

Fab*_*ioL 2

正如另一篇 SO 帖子中所建议的,一个原因可能是:

\n\n
\n

使用生成器表达式会导致不断暂停和恢复生成器的开销。

\n
\n\n

无论如何,我建议使用另两种看起来更快的方法map

\n\n
def are_all_identical_map(dataset):\n    for x in map(lambda x: x == dataset[0], dataset):\n        if not x:\n            return False\n    return True\n\n%%timeit\nare_all_identical_map(testDataset)\n#7.5 ms \xc2\xb1 64.3 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 100 loops each)\n
Run Code Online (Sandbox Code Playgroud)\n\n

\n\n
%%timeit\n(map(lambda x: x == dataset[0], dataset)) and True\n#303 ns \xc2\xb1 13.4 ns per loop (mean \xc2\xb1 std. dev. of 7 runs, 1000000 loops each)\n
Run Code Online (Sandbox Code Playgroud)\n