当前位置: 首页 > 后端技术 > Python

结合迭代器和生成器,内置函数enumerate()真的很好吃!

时间:2023-03-25 23:08:18 Python

花猫语:Python中的很多内置函数都非常好用,比如enumerate()和zip(),让我们做迭代操作非常方便。这是很多年前的PEP,提议在Python2.3中引入enumerate()。这篇文档综合了其他几个PEP(包括当时新推出的iterators和generators)的思想,提出了更好的实现方案和函数名。经过这么多年的发展,enumerate()不可避免地发生了一些变化,但不变的是它还是有必要的,好用的,真香的,就像19年前一样!PEP原文:https://www.python.org/dev/peps/pep-0279PEP标题:Theenumerate()built-infunctionPEP作者:RaymondHettinger创建日期:2002-06-30合并版本:2.3译者:Pea花在猫下@Python猫PEP翻译计划:https://github.com/chinesehuazhou/peps-cnAbstract本PEP引入了一个新的内置函数enumerate()来简化常用的循环编写。它赋予所有可迭代对象权力,就像字典的iteritems()一样——一种紧凑、可读、可靠的索引符号。基本原理Python2.2在PEP234[3]中引入了可迭代对象接口的概念。iter()工厂函数作为通用调用约定被提出,它深刻地修改了迭代器的使用方式,并作为整个Python的统一规范。这个统一的规范是为映射类型、序列类型和文件对象建立一个通用的可迭代对象接口。正如PEP255[1]中所提议的那样,生成器被引入作为创建迭代器的一种更简单的方法,尤其是具有复杂内部执行或可变状态的迭代器。使用生成器,PEP212[2]中循环计数器的想法可能会得到改进。这些想法是提供一个干净的迭代语法,带有索引和值,但不是针对所有可迭代对象。此外,该方法没有生成器提供的内存友好优势(生成器不会立即计算整个序列)。(Python猫注:关于生成器的PEP也有翻译,请看PEP-255、PEP-342、PEP-380)新的提议是增加一个内置函数enumerate(),在有了迭代器和生成器之后,它它是可以实现的。它赋予所有可迭代对象权力,就像字典的iteritems()一样——一种紧凑、可读、可靠的索引符号。与zip()一样,它有望成为常用的循环习惯用法。(Python猫注:zip()函数很强大,推荐阅读《一篇文章掌握 Python 内置 zip() 的全部内容》)本提案的目的是利用已有的实现,再加一点力气进行整合。它是向后兼容的,不需要新的关键字。该提案将合并到Python2.3中,并且不需要从\_\_future\_\_导入。新内置函数的规范defenumerate(collection):'生成索引系列:(0,coll[0]),(1,coll[1])...'i=0it=iter(collection)while1:yield(i,it.next())i+=1NoteA:PEP212LoopCounterIterations[2]讨论了实现索引的几个提议。一些提案只适用于列表,不像上面的函数适用于任意生成器、xranges、序列或可迭代对象。此外,这些提案是在Python2.2之前制定和评估的,但Python2.2不包括生成器。因此,PEP212中的非生成器版本存在使用大量元组列表的缺点,这会消耗太多内存。此处介绍的生成器版本快速且轻量级,适用于所有可迭代对象,并允许用户在不浪费计算的情况下中止。还有一些涵盖相关问题的PEP:整数迭代器、整数for循环,以及修改range和xrange参数的PEP。enumerate()提议并不排斥其他提议,即使那些提议被采纳,它仍然会满足一个重要的要求——需要对任意可迭代对象中的元素进行计数。其他提案给出了生成索引的方法,但没有对应的值。如果给定的序列不支持随机访问,例如文件对象、生成器或使用\_\_getitem\_\_定义的序列,这尤其有问题。注B:几乎所有的PEP评论者都欢迎这个功能,但对于是否应该内置它存在分歧。一方面提出使用独立模块,主要是为了减缓语言扩展的速度。对方提出使用内置函数,主要原因是该函数符合Python核心编程风格,适用于任何具有可迭代接口的对象。正如zip()解决了在多个序列上循环的问题,enumerate()函数解决了在计数器上循环的问题。如果只允许一个内置函数,那么enumerate()将是最重要的通用工具,它可以解决最广泛的问题,同时提高程序的简单性、清晰度和可靠性。NoteC:Variousalternativenamesdiscussed:functionnameanalysisiterindexed()五音节太啰嗦index()好动词,但可能与.index()方法混淆indexed()很流行,但应该避免for循环中的形容词indexer(),名词读起来不太好valueconceptconflictitemize()让人迷惑,因为amap.items()!=list(itemize(amap))enum()简洁;不像枚举那么清楚;与其他语言中的枚举太相似,但含义不同所有涉及“count”的名称也有暗示计数从1而不是0开始的缺点。名称中对“index”的所有引用都与用法冲突数据库语言,数据库的索引表示排序操作,而不是线性排序。注意D:在最初的提案中,此函数采用可选的启动和停止参数。GvR指出,函数enumerate(seqn,4,6)也有一个合理的解释,它返回序列的第4个和第5个元素的切片。为了避免歧义,这两个可选参数已被删除,尽管这意味着循环计数器失去了一些灵活性。在从1开始计数的常见用例中,这个可选参数的写法非常有用,比如:forlinenum,lineinenumerate(source,1):printlinenum,line(Python猫注:这篇文档说enumerate没有开始和结束参数,不过在后续版本中(比如我用的3.9),支持使用可选的开始参数!这个变化是什么时候加的我还没查到,有知道的请告知,这样就修复了!)GvR评论:filter和map应该消亡,包含在列表推导中,不再添加变体。我宁愿引入执行迭代器运算的内置函数(例如iterzip,我经常引用它作为示例)。我赞同以某种方式并行遍历序列及其索引的想法。让它成为一个内置的,没问题。我不喜欢“索引”这个名字;形容词不是一个好的函数名。可以使用iterindexed()吗?Ka-PingYee评论道:我也很高兴你的提议......添加的内置功能(倾向于使用“索引”)是我期待已久的东西。NeilSchenmauer评论道:新的内置功能听起来不错。Guido可能担心添加太多内置对象。你最好让它们成为模块的一部分。如果你使用模块,那么你可以添加很多有用的函数(Haskell有很多,我们可以“偷”)。MagnusLieHetland评论道:我认为indexed将是一个有用且自然的内置函数。我肯定会经常使用它。我真的很喜欢indexed();+1。很高兴它淘汰了PEP-281。为迭代器添加一个单独的模块似乎是个好主意。来自社区的反馈:几乎100%支持enumerate()提案。几乎每个人都喜欢这个主意。作者注:在这些评论之前,总共提出了四个内置函数。评论后,xmap、xfilter、xzip撤回。剩下的一个对Python至关重要。Indexed()非常容易实现并立即记录下来。更重要的是,它在日常编程中很有用,没有它,生成器就需要显式使用。该提案最初包含另一个函数iterzip()。但它后来在itertools模块中作为izip()函数实现。参考资料1,PEP255SimpleGeneratorshttp://www.python.org/dev/peps/pep-02552,(1,2)PEP212LoopCounterIterationhttp://www.python.org/dev/peps/pep-02123,PEP234迭代器http://www.python.org/dev/peps/pep-0234版权所有本文档已进入公共领域。源文件:https://github.com/python/peps/blob/master/pep-0279.txt