【问题标题】:Performance of loops, list comprehensions and maps in Python 3Python 3 中循环、列表推导和映射的性能
【发布时间】:2018-12-03 23:11:44
【问题描述】:

如何正确比较 Python 3.6 中 for 循环、列表解析和映射的性能?

在下面的代码中,普通的 for 循环执行得非常好(我使用 list() 从生成器获取值)。我在这里做错了吗?结果与discussion on Python 2形成鲜明对比。

import timeit

code_for = """
for i in range(1000):
    hex(i)
"""

code_map = """
list(map(hex, range(1000)))
"""

code_map_lambda = """
list(map(lambda x: hex(x), range(1000)))
"""

code_list_comprehension = """
[hex(x) for x in range(1000)]
"""

print(timeit.timeit(code_for, number=10000))
# 1.1155821208376437

print(timeit.timeit(code_map, number=10000))
# 0.8820606248918921

print(timeit.timeit(code_map_lambda, number=10000))
# 1.7510833400301635

print(timeit.timeit(code_list_comprehension, number=10000))
# 1.1798800542019308

更新:将元素添加到 code_for 中的列表

code_for_2 = """
a = [0] * 1000
for i in range(1000):
    a[i] = hex(i)
"""
# 1.243549756007269

code_for_3 = """
a = []
for i in range(1000):
    a.append(hex(i))
"""
# 1.5462996119167656    

【问题讨论】:

    标签: python python-3.x performance benchmarking


    【解决方案1】:

    几点建议:

    1. 为了清晰起见,将代码包装在函数中。
    2. 您缺少列表创建并在code_for 中追加。这是使用显式 for 循环的大部分成本。
    3. 然后您可以使用timeit,或者如果您有Jupyter notebook,则可以使用神奇的%timeit 命令。

    如下所示,没有lambda 的map 表现最好,这是有道理的,因为hex 是内置的。详情请见Python List Comprehension Vs. Map。

    def code_for(n):
        res = []
        for i in range(n):
            res.append(hex(i))
        return res
    
    def code_map(n):
        return list(map(hex, range(n)))
    
    def code_map_lambda(n):
        return list(map(lambda x: hex(x), range(n)))
    
    def code_list_comprehension(n):
        return [hex(x) for x in range(n)]
    
    %timeit code_for(10000)                 # 3.19 ms per loop
    %timeit code_map(10000)                 # 1.69 ms per loop
    %timeit code_map_lambda(10000)          # 3.06 ms per loop
    %timeit code_list_comprehension(10000)  # 2.27 ms per loop
    

    【讨论】:

    • 感谢您的回复!您能否解释一下为什么 list(map(...)) 等同于 append() 而不是在预分配列表中设置值?
    • 它们当然不是等价的(因此存在性能差异)。但结果是相同的,因为它们都输出列表。如果您不使用list.append,code_for 将不会返回任何内容,它会将hex 应用于每个项目,但结果将永远丢失。您应该查看this post,了解有关这些性能差异的一般详细信息。
    • 我在问,因为使用预先分配的列表,code_for 的结果与根本没有将元素放入列表中的结果相同。当然,append() 更慢。
    • @Konstantin,对不起,我不明白。为什么假设列表是使用这些方法中的任何一种预先分配的?
    • 请参考code_for_2和code_for_3。但似乎真的很难说 list(map(...)) 的幕后发生了什么。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-26
    • 1970-01-01
    • 2011-02-11
    • 2017-04-19
    • 2018-10-23
    • 2014-10-27
    相关资源
    最近更新 更多