2

可能重复:
sorted() 使用生成器表达式而不是列表

我们都知道使用生成器而不是一直实例化列表可以节省时间和内存,尤其是在我们大量使用推导式的情况下。

这是一个问题,请考虑以下代码:

output = SomeExpensiveCallEgDatabase()
results = [result[0] for result in output]
return sorted(results)

对 sorted 的调用将返回结果的排序列表。如下声明结果然后调用排序是更好还是更糟?

results = (result[0] for result in output)

我的猜测是对 sorted() 的调用将遍历生成器并实例化一个列表本身,以便对其运行快速排序或合并排序。所以在这里使用生成器没有任何优势。这个假设正确吗?

4

3 回答 3

3

我相信你的假设是正确的,因为没有先将整个列表放在内存中就没有简单的方法来排序集合(至少肯定不是默认排序算法,如果我没记错的话,TimSort)。

看看这个: sorted() 使用生成器表达式而不是列表

要创建新列表,内置的 sorted 方法使用PySequence_List

PyObject* PySequence_List(PyObject *o) 返回值:新引用。返回与任意序列 o 内容相同的列表对象。返回的列表保证是新的。

两种方法的优缺点:

内存方面:

返回的列表是用于排序版本的列表,因此这意味着在这种情况下,在任何给定时间,只有一个列表完全存储在内存中,使用生成器版本。

这使得生成器版本在内存方面更有效率。

速度:

在这里,具有整个列表的版本获胜。

要基于生成器创建新列表,必须创建一个空列表(或最多使用第一个元素),并将每个后续元素附加到列表中,这可能会引发可能的重新尺寸调整步骤。

要基于以前的列表创建新列表,列表的大小是事先知道的,因此可以一次分配并分配每个条目(可能,这里还有其他优化工作,但我不能回那个)。

因此,关于速度,列表获胜。

“什么是最好的”的答案归结为任何工程领域中最常见的答案......这取决于......

于 2012-08-03T11:02:30.323 回答
3

不,您仍在创建一个全新的列表sorted()

output = SomeExpensiveCallEgDatabase()
results = [result[0] for result in output]
results.sort()
return results

将更接近生成器版本。

我相信最好使用生成器版本,因为 Python 的某些未来版本可能能够利用这一点来更有效地工作。免费获得加速总是很好的。

于 2012-08-03T11:03:27.140 回答
0

是的,你是对的(虽然我相信排序例程仍然称为 tim-sort,在 uncle timmy <wink-ly y'rs> 之后)

于 2012-08-03T11:02:10.330 回答