为什么 `zip` 会从第一个迭代器中多吃一个元素?

问题描述

我正在学习 Effective Python(第 2 版)中的第 76 条,但遇到了一个我不理解的案例。具体来说,我不明白为什么 CREATE TABLE 会消耗其第一个参数的一个额外元素。考虑以下代码

zip

这实际上打印了 l1 = [] l2 = [1] l1_it = iter(l1) l2_it = iter(l2) test_it = zip(l2_it,l1_it) _ = list(test_it): try: next(l2_it) except stopiteration: print('This should not happen') ,我觉得这非常令人惊讶。我希望 This should not happen 将其第一个参数保留在仍有一个元素要检索的状态。事实是,如果我使用 zip(即最短的列表在前),那么我确实可以调用 zip(l1_it,l2_it) 而不会触发异常。

这是预期的吗?

解决方法

zip 取最短迭代的长度并限制于此。由于 l1 没有项目,因此不会处理 l2 中的项目。

然而......使用可迭代的 Python 不知道有多少项目可用,所以它唯一的办法就是尝试获取一个项目。如果没有项目,它会得到一个例外。如果有一个项目,它现在已经从迭代器中消费了它。

也许您期待 zip_longest 的行为? https://docs.python.org/3/library/itertools.html?highlight=itertools#itertools.zip_longest

为了说明 iter() 行为:

>>> x = [1]
>>> x_iter = iter(x)

# We cannot get the length and unless we are prepared to fetch it,# we cannot check if there are items available.
>>> len(x_iter)
Traceback (most recent call last):
  File "<stdin>",line 1,in <module>
TypeError: object of type 'list_iterator' has no len()

# First item can be fetched
>>> next(x_iter)
1

# There is no second item so Python raises a StopIteration
>>> next(x_iter)
Traceback (most recent call last):
  File "<stdin>",in <module>
StopIteration