【问题标题】:Is it reasonable to say that list comprehension is not necessarily faster than for loop way in some cases?在某些情况下,列表理解不一定比 for 循环方式更快,这是否合理?
【发布时间】:2019-08-16 09:47:28
【问题描述】:

Python doc

列表推导式提供了一种创建列表的简洁方式。

Python doc 好像没有说(可能这个说法不正确,如果需要请修正)

“列表推导比 for 循环更快”

这里有两个函数

def find_base_match_v1(char, matrix):
    base_matches = []
    for row_index, row in enumerate(matrix):
        for column_index, column in enumerate(row):
            if char == column:
                base_matches.append((row_index, column_index))
    return base_matches

def find_base_match_v2(char, matrix):
    base_matches = [(row_index, column_index)
                    for row_index, row in enumerate(matrix)
                    for column_index, column in enumerate(row)
                    if char == column]
    return base_matches

函数v1的性能(for循环方法)

timeit "find_base_match_v1('d', grid)"

10.6 ns ± 0.419 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)

函数v2的性能(列表理解方法)

timeit "find_base_match_v2('d', grid)"

12.1 ns ± 1.74 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)

有时结果是相反的,v2 比 v1 快一点。

无论如何,不​​能保证哪一个一定比另一个快,我的理解对吗?

【问题讨论】:

  • 简洁,即打字和阅读更短。没有任何关于以一种或另一种方式表现的说法......
  • 您确定您测量的是函数调用而不仅仅是字符串创建吗?即使是空网格的函数调用也会在我的机器上使用453 ns

标签: python list-comprehension


【解决方案1】:

列表推导并不神奇。查看您的代码:它读取一个矩阵并存储 元素的坐标等于给定的字符:

matrix1 = [['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']]
print(timeit.timeit(lambda: find_base_match_v1('f', matrix1)))
# 1.002808532999552
print(timeit.timeit(lambda: find_base_match_v2('f', matrix1)))
# 1.0684777589995065

时间几乎一样,原因很明显:构建的列表很小

print(find_base_match_v1('f', matrix1))
# [(1, 2)]
print(find_base_match_v2('f', matrix1))
# [(1, 2)]

如果你构建一个更大的列表,假设有一百个元素,列表理解会胜过 for 循环(Ubuntu 上的 CPython 3.6):

matrix2 = [['f']*10 for _ in range(10)]
print(find_base_match_v1('f', matrix2))
# [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (0, 7), (0, 8), (0, 9), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (2, 9), (3, 0), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (3, 6), (3, 7), (3, 8), (3, 9), (4, 0), (4, 1), (4, 2), (4, 3), (4, 4), (4, 5), (4, 6), (4, 7), (4, 8), (4, 9), (5, 0), (5, 1), (5, 2), (5, 3), (5, 4), (5, 5), (5, 6), (5, 7), (5, 8), (5, 9), (6, 0), (6, 1), (6, 2), (6, 3), (6, 4), (6, 5), (6, 6), (6, 7), (6, 8), (6, 9), (7, 0), (7, 1), (7, 2), (7, 3), (7, 4), (7, 5), (7, 6), (7, 7), (7, 8), (7, 9), (8, 0), (8, 1), (8, 2), (8, 3), (8, 4), (8, 5), (8, 6), (8, 7), (8, 8), (8, 9), (9, 0), (9, 1), (9, 2), (9, 3), (9, 4), (9, 5), (9, 6), (9, 7), (9, 8), (9, 9)]

print(timeit.timeit(lambda: find_base_match_v1('f', matrix2)))
# 9.212440792000052
print(timeit.timeit(lambda: find_base_match_v2('f', matrix2)))
# 6.918398160998549

但正如评论中所写,文档不保证这一点。 更多信息请见:Are list-comprehensions and functional functions faster than "for loops"?

【讨论】:

    猜你喜欢
    • 2014-04-02
    • 1970-01-01
    • 2017-09-26
    • 1970-01-01
    • 2019-12-16
    • 2017-01-23
    • 1970-01-01
    • 2011-04-30
    相关资源
    最近更新 更多