python - 为什么将列表作为参数传递比传递生成器性能更好?

标签 python list time generator

我正在回答 this question ,当我测试解决方案的时间时,我发现了与我认为正确的矛盾。

提出问题的人想要找到一种方法来知道另一个列表中包含多少个不同的列表。 (了解更多信息,您可以check the question)

我的回答基本上是这个函数:

def how_many_different_lists(lists):
    s = set(str(list_) for list_ in lists)
    return len(s)

现在,当我测量运行时间并将其与基本相同的函数进行比较时,情况出现了,但将列表而不是生成器作为参数传递给 set():

def the_other_function(lists):
    s = set([str(list_) for list_ in lists])
    return len(s)

这是我用来测试函数的装饰器:

import time

def timer(func):
    def func_decorated(*args):
        start_time = time.clock()
        result = func(*args)   
        print(time.clock() - start_time, "seconds")
        return result
    return func_decorated

这是给定输入的结果:

>>> list1 = [[1,2,3],[1,2,3],[1,2,2],[1,2,2]]
>>> how_many_different_lists(list1)
6.916326725558974e-05 seconds
2
>>> the_other_function(list1)
3.882067261429256e-05 seconds
2

即使对于较大的列表:

# (52 elements)
>>> list2= [[1,2,3],[1,2,3],[1,2,2],[1,2,2],[1,2,3],[1,2,3],[1,2,2],[1,2,2],[1,2,3],[1,2,3],[1,2,2],[1,2,2],[1,2,3],[1,2,3],[1,2,2],[1,2,2],[1,2,3],[1,2,3],[1,2,2],[1,2,2],[1,2,3],[1,2,3],[1,2,2],[1,2,2],[1,2,3],[1,2,3],[1,2,2],[1,2,2],[1,2,3],[1,2,3],[1,2,2],[1,2,2],[1,2,3],[1,2,3],[1,2,2],[1,2,2],[1,2,3],[1,2,3],[1,2,2],[1,2,2],[1,2,3],[1,2,3],[1,2,2],[1,2,2],[1,2,3],[1,2,3],[1,2,2],[1,2,2],[1,2,3],[1,2,3],[1,2,2],[1,2,2]]
>>> how_many_different_lists(list2)
0.00023560132331112982 seconds
2
>>> the_other_function(list2)
0.00021329059177332965 seconds
2

现在,我的问题是:为什么第二个示例比第一个示例更快?由于“按需”生产元素,发电机难道不应该更快吗?我曾经认为创建一个列表并迭代它会比较慢。

PS:我已经测试了很多次,得到的结果基本相同。

最佳答案

我一直在对你的功能进行基准测试:

enter image description here

from simple_benchmark import BenchmarkBuilder
from random import choice

b = BenchmarkBuilder()
from operator import setitem


@b.add_function()
def how_many_different_lists(lists):
    s = set(str(list_) for list_ in lists)
    return len(s)


@b.add_function()
def the_other_function(lists):
    s = set([str(list_) for list_ in lists])
    return len(s)


@b.add_arguments('Number of lists in the list')
def argument_provider():
    for exp in range(2, 18):
        size = 2**exp

        yield size,  [list(range(choice(range(100)))) for _ in range(size)]


r = b.run()
r.plot()

生成器是惰性的,因为生成器表达式将动态创建项目,而列表理解将在内存中创建整个列表。您可以在这里阅读更多信息:Generator Expressions vs. List Comprehension

正如您从基准测试中看到的那样,它们之间没有那么大的差异。

关于python - 为什么将列表作为参数传递比传递生成器性能更好?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59995236/

相关文章:

python - 如何将对象追加到实例变量列表中?

python - 用来自同一行但不同列的值填充字典

Python:将for循环与列表相关联

java - Thread中List的内存范围

java - 在特定时间执行java代码

r - 在 R 中按天绘制时间间隔

windows - 如何测量 Windows 命令行上命令的执行时间?

python - 如何填写表格初始数据?

python - sklearn 线性回归中的 n_jobs

python - Pandas : how to merge 2 dataframes on key1. str.endswith(key2)