在Python 3中,许多返回列表的函数(现在是类)现在返回迭代,最常见的例子是range
。在这种情况下,范围在Python 3中是可迭代的,以提高性能和内存效率(因为您不必再构建列表)。
其他“新”可迭代是map
,enumerate
,zip
以及字典操作dict.keys()
,dict.values()
和dict.items()
的输出。 (可能还有更多,但我不知道)。
其中一些(enumerate
和map
)通过将它们转换为可迭代内容而变得更具内存效率。在Python 2.7中,其他人只是创建了已经在内存中的对象列表,因此它们可以提高内存效率。
为什么然后将它们转换为每次要对它们进行排序时必须转换为列表的迭代项?等等。
答案 0 :(得分:9)
有几个原因:
字典操作现在返回dictionary view objects;这些也可以作为集合,为您提供更丰富的对象,以便在您的代码中使用。在Python 2中,您必须使用dict.view*()
方法来执行相同的操作。
Python 2中的字典操作产生了一个新的列表对象;即使索引引用现有对象,列表对象也会占用内存。这里还有另一个副作用;列表索引会增加所有这些字典内容的引用计数,这也会影响性能(并且可能会刷新CPU缓存)。
zip()
和map()
可以始终处理任何迭代,包括生成器,但是在应用时会将所有内容都拉到一个大的列表中。通过在Python 3中将它们转换为生成器,它们不再自动消耗这样的迭代。
请注意,Python 2中的enumerate()
从未返回一个列表,它总是返回一个迭代器。
只需在这些对象上应用list()
,就可以始终获得旧的Python 2行为。如果您需要排序的项目,则可以在iterable上调用sorted()
。但是你现在有选择,而不是强迫你使用列表对象。
对于Python中的大多数用例,您从未真正需要一个完整的列表。您通常会迭代这些结果。对它们进行排序不是最常见的用例,索引它们也不是。因此,对于大多数用例而言,这种变化是一种胜利,它为程序员提供了工具,可以使用标准函数和类型生成更高效的代码。
答案 1 :(得分:4)
如果要对它们进行排序,则需要将iterable转换为一个列表(sorted
将为您处理)...但是您要多久对一个enumerate
对象进行排序,与您经常迭代它的频率相比?如何对dict的items
进行排序,而不是迭代它们?
如果您的API生成了一个惰性迭代器或其他惰性迭代器,您可以将其转换为一个列表,与跳过迭代器并直接生成列表所花费的工作量大致相同。另一方面,如果您的API生成一个列表,则无法避免一次性将所有项目保留在内存中。迭代器更灵活。