除了 zip(range(len())) 之外,还有更多的 enumerate() 吗?

Is there more to enumerate() than just zip(range(len()))?

Python 中的一切都是有原因的。 Python 支持的所有系统都依赖于大约 50 个内置函数,其中大部分非常有用 和独特的 ,例如 format()len()list()range()我不明白为什么 enumerate() 存在

已在 PEP 279 (2002) and was kept until now. I really don't understand why it exists because it can be done using other more important built-in functions in 2-3 characters more. From the 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() 是否有一些我没有看到的独特功能。

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

>>> 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() 的长度,但您可以 enumerate 通过 next(或迭代)获取所有输入。

我看到的最大问题是 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)

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

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

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

V.S

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

此外,使用len是增加了另一个不必要的操作。虽然包含 enumerate 消除了从库中导入这种简单需求的需要。