Python 3 中的迭代器
Posted
技术标签:
【中文标题】Python 3 中的迭代器【英文标题】:Iterators in Python 3 【发布时间】:2014-04-04 13:26:09 【问题描述】:在 Python 3 中,许多返回列表的函数(现在是类)现在都返回可迭代对象,最流行的例子是 range
。在这种情况下,在 Python 3 中将 range 设置为可迭代的,以提高性能和内存效率(因为您不再需要构建列表)。
其他“新”迭代是map
、enumerate
、zip
和字典操作的输出dict.keys()
、dict.values()
和dict.items()
。 (可能还有更多,但我不知道)。
其中一些(enumerate
和 map
)通过将它们转换为可迭代对象,可能会提高内存效率。在 Python 2.7 中,其他人只是简单地创建了已经在内存中的对象列表,因此它们本来可以节省内存。
为什么然后将它们转换为每次要对它们进行排序等时都必须转换为列表的可迭代对象?
【问题讨论】:
enumerate()
在 Python 2 中已经是一个可迭代对象了。
创建列表对象的内存效率不高; list
对象是一个新对象。
【参考方案1】:
几个原因:
字典操作现在返回dictionary view objects;它们也充当集合,为您提供更丰富的对象以在您的代码中使用。在 Python 2 中,您必须使用 dict.view*()
方法来做同样的事情。
Python 2 中的字典操作产生了一个新的列表对象;即使索引引用现有对象,该列表对象也会占用内存。这里还有另一个副作用;列表索引会增加所有这些字典内容的引用计数,这也会影响性能(并可能刷新 CPU 缓存)。
zip()
和 map()
始终可以在任何可迭代对象(包括生成器)上工作,但在应用时会将所有内容拉到一个大列表中。通过在 Python 3 中将它们变成生成器,它们不再自动使用此类可迭代对象。
请注意,Python 2 中的 enumerate()
从未返回列表,它始终返回一个迭代器。
您总是可以通过在此类对象上应用list()
来获得旧的 Python 2 行为。如果您需要排序的项目,您可以在可迭代对象上调用 sorted()
。但是您现在有了选择,而不是强加给您的列表对象。
对于 Python 中的大多数 用例,您从不需要一个完整的列表开始。您通常会迭代此类结果。对它们进行排序不是最常见的用例,对它们进行索引也不是。因此,对于大多数用例而言,这种变化是一种胜利,它为程序员提供了工具,可以仅使用标准函数和类型来生成更高效的代码。
【讨论】:
另外,构建视图需要增加 dict 的引用计数,而构建列表意味着增加所有对象的引用计数。使用大字典,这是刷新 CPU 缓存的有效方法。 "通过将它们变成“生成器”——使map
、filter
和 zip
的“迭代器”成为“迭代器”。仅供 OP 使用,range
是一个序列,而不是只是一个可迭代的。【参考方案2】:
如果您想对它们进行排序,则需要将可迭代对象转换为列表(sorted
将为您处理)...但是与频率相比,您打算多久对 enumerate
对象进行排序你要迭代它吗?与仅对它们进行迭代相比,对字典的items
进行排序怎么样?
如果您的 API 生成惰性迭代器或其他惰性迭代器,您可以将其转换为列表,其工作量与跳过迭代器并直接生成列表所花费的精力大致相同。另一方面,如果您的 API 生成一个列表,则无法避免一次将所有项目保存在内存中。迭代器更灵活。
【讨论】:
sorted()
如果你想要一个排序的副本也可以。
@MartijnPieters:我可能应该更清楚地说“你需要创建一个列表”,我的意思是“需要创建一个列表”,而不是“你需要致电 @987654325 @就可以了”。以上是关于Python 3 中的迭代器的主要内容,如果未能解决你的问题,请参考以下文章