Following system colour scheme - Python 增强提案 Selected dark colour scheme - Python 增强提案 Selected light colour scheme - Python 增强提案

Python 增强提案

PEP 279 – enumerate() 内置函数

作者:
Raymond Hettinger <python at rcn.com>
状态:
最终版
类型:
标准跟踪
创建日期:
2002年1月30日
Python 版本:
2.3
发布历史:


目录

摘要

本 PEP 引入了一个新的内置函数 enumerate(),以简化常用循环习语。它为所有可迭代集合提供了与 iteritems() 为字典提供的相同优势——一种紧凑、可读、可靠的索引表示法。

基本原理

Python 2.2 引入了可迭代接口的概念,如 PEP 234 中所提议。提供了 iter() 工厂函数作为常见的调用约定,并进行了深入的更改,以将迭代器作为 Python 中的统一主题。这种统一以建立映射、序列和文件对象的通用可迭代接口的形式实现。

生成器,如 PEP 255 中所提议,被引入作为更容易创建迭代器的方法,特别是那些具有复杂内部执行或可变状态的迭代器。生成器的可用性使得改进 PEP 212 中循环计数器思想成为可能。这些思想为带索引和值的迭代提供了清晰的语法,但并不适用于所有可迭代对象。此外,这种方法不具备生成器提供的内存友好优势,因为生成器不会一次性评估整个序列。

新的提案是添加一个内置函数 enumerate(),这在迭代器和生成器可用后成为可能。它为所有可迭代对象提供了与 iteritems() 为字典提供的相同优势——一种紧凑、可读、可靠的索引表示法。与 zip() 一样,它有望成为常用的循环习语。

此建议旨在利用现有实现,并且只需少量额外工作即可集成。它向后兼容,不需要新的关键字。该提案将在 Python 2.3 中实现,届时生成器将最终确定且不再从 __future__ 导入。

BDFL 公告

新内置函数已获接受。

新内置函数的规范

def enumerate(collection):
   'Generates an indexed series:  (0,coll[0]), (1,coll[1]) ...'
   i = 0
   it = iter(collection)
   while 1:
      yield (i, it.next())
      i += 1

注 A:PEP 212 循环计数器迭代讨论了实现索引的几种提案。其中一些提案仅适用于列表,而不像上述函数那样适用于任何生成器、xrange、序列或可迭代对象。此外,这些提案是在 Python 2.2 之前的世界中提出和评估的,当时不包括生成器。因此,PEP 212 中的非生成器版本具有消耗内存(带有巨大的元组列表)的缺点。此处提出的生成器版本快速轻巧,适用于所有可迭代对象,并允许用户在过程中放弃序列而不会损失计算工作。

还有其他 PEP 涉及相关问题:整数迭代器、整数 for 循环,以及一个用于修改 rangexrange 参数的提案。enumerate() 提案不排除其他提案,即使采纳了这些提案,它仍然满足一个重要需求——计算任何可迭代对象中的项目。其他提案提供了一种生成索引的方法,但没有提供相应的值。如果给定不支持随机访问的序列,例如文件对象、生成器或使用 __getitem__ 定义的序列,这尤其成问题。

注 B:几乎所有 PEP 评审者都欢迎此函数,但在是否应该有任何内置函数的问题上存在分歧。支持独立模块的主要论点是减缓语言膨胀的速度。支持内置函数的主要论点是该函数注定会成为核心编程风格的一部分,适用于任何具有可迭代接口的对象。正如 zip() 解决了遍历多个序列的问题一样,enumerate() 函数解决了循环计数器问题。

如果只允许一个内置函数,那么 enumerate() 是最重要的通用工具,它解决了最广泛的问题,同时提高了程序的简洁性、清晰度和可靠性。

注 C:讨论了各种替代名称

iterindexed() 五个音节太拗口
index() 不错的动词,但可能与 .index() 方法混淆
indexed() 广受欢迎,但应避免使用形容词
indexer() 名词在 for 循环中读起来不好听
count() 直接明确,但常用于其他上下文
itercount() 直接、明确,但被不止一人讨厌
iteritems() 与字典的键值概念冲突
itemize() 令人困惑,因为 amap.items() != list(itemize(amap))
enum() 简洁;不如 enumerate 清晰;与其他语言中具有不同含义的 enum 太相似

所有涉及“count”的名称还有一个缺点,即暗示计数将从一开始而不是从零开始。

所有涉及“index”的名称都与数据库语言中的用法冲突,其中索引意味着排序操作而不是线性排序。

注 D:此函数最初提议带有可选的 start 和 stop 参数。GvR 指出,函数调用 enumerate(seqn,4,6) 有另一种合理的解释,即作为切片,它将返回序列的第四和第五个元素。为了避免歧义,即使这意味着失去作为循环计数器的灵活性,可选参数也被放弃了。这种灵活性对于从一开始计数的常见情况最为重要,例如

for linenum, line in enumerate(source,1):  print linenum, line
来自 GvR 的评论
filtermap 应该消亡并被列表推导式取代,而不是增加更多变体。我宁愿引入执行迭代器代数(例如我经常用作示例的 iterzip)的内置函数。

我喜欢以某种方式并行迭代序列及其索引集的想法。这作为内置函数很好。

我不喜欢“indexed”这个名字;形容词不是好的函数名。也许 iterindexed()

来自 Ka-Ping Yee 的评论
我也非常满意你提出的所有建议……而且那些额外的内置函数(特别是 'indexed')是我长期以来一直想要的。
来自 Neil Schemenauer 的评论
新的内置函数听起来不错。Guido 可能担心内置函数数量增加过多。你最好将它们作为模块的一部分来推广。如果你使用模块,那么你可以添加许多有用的函数(Haskell 有很多我们可以借鉴的)。
来自 Magnus Lie Hetland 的评论
我认为 indexed 将是一个有用且自然的内置函数。我肯定会大量使用它。我非常喜欢 indexed();+1。我很高兴它能使 PEP 281 过时。为迭代器实用程序添加一个单独的模块似乎是个好主意。
来自社区的评论
enumerate() 提案的反应几乎 100% 支持。几乎所有人都喜欢这个想法。
作者回应
在这些评论之前,曾提议四个内置函数。评论之后,xmapxfilterxzip 被撤回。剩下的那个对语言至关重要,并被单独提出。Indexed() 实现起来极其简单,可以在几分钟内完成文档。更重要的是,它在日常编程中非常有用,而这些编程通常不涉及明确使用生成器。

此提案最初还包括另一个函数 iterzip()。该函数随后在 itertools 模块中实现为 izip() 函数。


来源:https://github.com/python/peps/blob/main/peps/pep-0279.rst

最后修改:2025-02-01 08:55:40 GMT