【问题标题】:Is there more to enumerate() than just zip(range(len()))?enumerate() 不仅仅是 zip(range(len())) 吗?
【发布时间】:2020-05-29 16:15:51
【问题描述】:

Python 中的一切都是有原因的。所有由 Python 提供支持的系统都依赖于类似 50 个内置函数,其中大多数都非常有用并且是独一无二的,例如 format()len()list()range()我不明白为什么enumerate() 存在

它已在PEP 279 (2002) 中引入并一直保留到现在。我真的不明白它为什么存在,因为它可以使用其他更重要的内置函数在 2-3 个字符中完成。来自Python Docs

seasons = ['Spring', 'Summer', 'Fall', 'Winter']
for i in enumerate(seasons):
    print(i)

使用更重要的内置函数的实现是这样的:

for i in zip(range(len(seasons)), seasons):
    print(i)
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]

这两个是一样的,我们都知道zip()range() 的重要性。那么,为什么要添加一个看起来除了这两个之外没有任何价值的内置函数呢?

Python Docs中,这里相当于enumerate()

def enumerate(sequence, start=0):
    n = start
    for elem in sequence:
        yield n, elem
        n += 1

底线:我想知道enumerate() 是否有一些我没有看到的独特功能。

【问题讨论】:

  • 我认为enumerate 和等效的zip(range(len... 混乱之间的可读性差异是不言而喻的。 :) 当您在技术上可以使用for 循环时,为什么还要进行列表推导?当您在技术上可以使用while 时,为什么还要使用for?等等。这一切都是为了能够优雅地表达常见的用例,而不需要大量的样板。
  • 另外,在您的替代方法中,您正在重复 seasons,这通常不是一件好事。所以enumerate还是更好。
  • 为什么要使用整个 itertools 模块,因为它只是您可以使用更原始的东西构建的食谱......?
  • 当您可以在 Malbolge 中编写所有代码时,为什么还有 Python 存在?
  • 您的灵活性如何?枚举不灵活怎么办?

标签: python string list enumerate


【解决方案1】:

因为不是每个可迭代对象都有长度。

>>> def countdown(x):
...     while x >= 0:
...         yield x
...         x -= 1
...         
>>> down = countdown(3)
>>> len(down)
Traceback (most recent call last):
[...]
TypeError: object of type 'generator' has no len()
>>> enum = enumerate(down)
>>> next(enum)
(0, 3)
>>> next(enum)
(1, 2)

当然,这是一个简单的例子。但我可以想到很多现实世界的对象,你无法合理地预先计算长度。要么是因为长度是无限的(请参阅itertools.count),要么是因为您正在迭代的对象本身不知道聚会何时结束。

您的迭代器可能正在从大小未知的远程数据库中获取数据块,或者连接可能会在没有警告的情况下丢失。或者它可以处理用户输入。

def get_user_input():
     while True:
        i = input('input value or Q to quit: ')
        if i == 'Q':
            break
        yield i

您无法获得get_user_input() 的长度,但您可以在通过next(或迭代)获取所有输入时enumerate

【讨论】:

    【解决方案2】:

    我看到的最大问题是Iterable 不一定是有限的。 len 对每个结构都没有意义:

    def infinite():
        n = 0
        while True:
            yield n
            n += 1
    
    for i, n in enumerate(infinite()):
        print(i, n)
    

    不可能使用您的实现来枚举infinite

    如果您使用infinite(或itertools.count)代替range,它会起作用:

    for i, n in zip(infinite(), seasons):
        print(i, n)
    

    但是,不幸的是,range 与 Clojure 等语言不同,它不可能是无限的。您必须指定结尾,这需要提前知道长度,这会使事情变得复杂。

    【讨论】:

      【解决方案3】:

      我觉得在这里使用itertools.count 作为enumerate 的替代品更合适,因为enumerate 不需要知道它只在迭代中提供下一个数字和下一个对象的长度。

      from itertools import count
      for i, o in zip(count(), iterable):
          ...
      

      V.S

      for i, o in enumerate(iterable):
          ...
      

      此外,使用len 会添加另一个不必要的操作。尽管包含 enumerate 消除了从库中导入此类简单需求的需要。

      【讨论】:

      • 我觉得这里面有答案:为什么要为如此常见的东西导入一个模块……
      猜你喜欢
      • 2022-06-15
      • 2019-03-28
      • 1970-01-01
      • 2021-09-02
      • 1970-01-01
      • 2015-01-03
      • 1970-01-01
      • 2012-05-11
      • 1970-01-01
      相关资源
      最近更新 更多