Python 中的 zip 对象不是迭代器吗?

Isn't zip object in Python an iterator?

我正在阅读 Bill Lubanovic 的 'Introducing Python',它说

Like zip(), range() returns an iterable object,

但这不是一个错误的说法吗?例如,

s= zip([1,2,3],['one','two','three'])
next(s)
>> (1,'one')
next(s)
>> (2,'two')

a = range(10)
next(a)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-54-7b3ad3809256> in <module>()
      1 a = range(10)
----> 2 next(a)

TypeError: 'range' object is not an iterator

从上面的代码中,我们可以检查 zip() returns 一个迭代器而不是一个可迭代对象。

"an iterator" 和 "iterable" 不是一回事。所有的迭代器都是可迭代的,但不是所有的迭代器都是迭代器。

iterables 可以传递给 iter(),returns 一个 iterator。 iterators 可以传递给 next(),也可以传递给 iter(),在这种情况下充当恒等函数。


https://docs.python.org/glossary.html#term-iterable

An object capable of returning its members one at a time. Examples of iterables include all sequence types (such as list, str, and tuple) and some non-sequence types like dict, file objects, and objects of any classes you define with an __iter__() or __getitem__() method. Iterables can be used in a for loop and in many other places where a sequence is needed (zip(), map(), …). When an iterable object is passed as an argument to the built-in function iter(), it returns an iterator for the object. This iterator is good for one pass over the set of values. When using iterables, it is usually not necessary to call iter() or deal with iterator objects yourself. The for statement does that automatically for you, creating a temporary unnamed variable to hold the iterator for the duration of the loop. See also iterator, sequence, and generator.

https://docs.python.org/glossary.html#term-iterator

An object representing a stream of data. Repeated calls to the iterator’s __next__() method (or passing it to the built-in function next()) return successive items in the stream. When no more data are available a StopIteration exception is raised instead. At this point, the iterator object is exhausted and any further calls to its __next__() method just raise StopIteration again. Iterators are required to have an __iter__() method that returns the iterator object itself so every iterator is also iterable and may be used in most places where other iterables are accepted. One notable exception is code which attempts multiple iteration passes. A container object (such as a list) produces a fresh new iterator each time you pass it to the iter() function or use it in a for loop. Attempting this with an iterator will just return the same exhausted iterator object used in the previous iteration pass, making it appear like an empty container.

迭代器是可迭代的。 zip return 是一个迭代器这一事实并不意味着它不是 return 一个可迭代的。此外,如果本书是为 Python 2 编写的,则 ziprange return 都在该版本中列出。

除了其他答案,您可能会发现 collections.abc 模块很有趣:

>>> from collections.abc import Iterable, Iterator
>>> issubclass(zip, Iterable)
True
>>> issubclass(zip, Iterator)
True
>>> issubclass(range, Iterable)
True
>>> issubclass(range, Iterator)
False

(还要注意 ziprange 是 类,不再起作用,所以说它们 "returning" 可以说是不准确的)