在Python 3中,许多返回列表的函数(现在是类)现在都返回可迭代项,最流行的例子是range
。在本例中,范围在Python3中被设置为可迭代的,以提高性能和内存效率(因为您不再需要构建列表)。
其他"新"可迭代项是map
、enumerate
、zip
以及字典操作dict.keys()
、dict.values()
和dict.items()
的输出。(可能还有更多,但我不知道)。
其中一些(enumerate
和map
)可能通过将它们转换为可迭代项而变得更具内存效率。在Python 2.7中,其他人只是创建了已经在内存中的对象列表,因此它们将具有内存效率。
为什么要把它们变成可迭代的,每次你想对它们进行排序时都必须将其转换为列表,等等。?
几个原因:
-
字典操作现在返回字典视图对象;这些也充当集合,为您的代码提供了更丰富的对象。在Python2中,您必须使用
dict.view*()
方法才能执行相同的操作。 -
Python 2中的dictionary操作生成了一个新的列表对象;即使索引引用了现有对象,该列表对象也会占用内存。这里还有另一个副作用;列表索引增加了所有这些字典内容的引用计数,这也会影响性能(并可能刷新CPU缓存)。
-
zip()
和map()
总是可以处理任何可迭代项,包括生成器,但在应用时会将所有内容都拉到一个大列表中。通过在Python3中将它们变成生成器,它们不再自动使用这样的迭代。
请注意,Python 2中的enumerate()
从未返回列表,它总是返回迭代器。
只需在此类对象上应用list()
,就可以获得旧的Python 2行为。如果您需要排序的项目,您可以在iterable上调用sorted()
。但现在您可以选择,而不是强制使用列表对象。
对于Python中的大多数用例,您根本不需要从一个完整的列表开始。您通常会对这样的结果进行迭代。对它们进行排序不是最常见的用例,对它们进行索引也不是。因此,对于大多数用例来说,这种更改是一种胜利,它为程序员提供了只使用标准函数和类型生成更高效代码的工具。
如果要对它们进行排序,则需要将可迭代项转换为列表(sorted
将为您处理)。。。但是,与对enumerate
对象进行迭代的频率相比,对其进行排序的频率是多少?与只对dict的items
进行迭代相比,对它们进行排序怎么样?
如果API生成一个懒惰迭代器或其他懒惰可迭代程序,则可以将其转换为一个列表,所需的工作量与跳过迭代器并直接生成列表所需的精力大致相同。另一方面,如果API生成一个列表,则无法避免同时将所有项保存在内存中。迭代器更灵活。