【问题标题】:Isn't zip object in Python an iterator?Python中的zip对象不是迭代器吗?
【发布时间】:2018-02-04 02:35:00
【问题描述】:

我正在阅读 Bill Lubanovic 的“Python 简介”,它说

和 zip() 一样,range() 返回一个可迭代对象,

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

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() 返回的是一个迭代器而不是一个可迭代的对象。

【问题讨论】:

  • 哪个 Python 版本?
  • @KlausD。我正在使用 Python 3.6.1,本书采用 Python 3
  • next(s) 返回(1,'one'),而不是1

标签: python iterator iterable


【解决方案1】:

“一个迭代器”和“可迭代”不是一回事。所有的迭代器都是可迭代的,但并非所有的可迭代都是迭代器。

iterables 可以传递给 iter(),它返回一个 iterator。 iterators 可以传递给next(),也可以传递给iter(),在这种情况下充当身份函数。


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

一个能够一次返回其成员的对象。可迭代对象的示例包括所有序列类型(例如liststrtuple)和一些非序列类型(例如dict)、文件对象以及您使用__iter__() 定义的任何类的对象或__getitem__() 方法。 Iterables 可用于 for 循环和许多其他需要序列的地方(zip()map(),...)。当可迭代对象作为参数传递给内置函数iter() 时,它会返回该对象的迭代器。此迭代器适用于遍历一组值。在使用迭代器时,通常不需要调用iter() 或自己处理迭代器对象。 for 语句会自动为您执行此操作,创建一个临时的未命名变量以在循环期间保存迭代器。另请参阅迭代器、序列和生成器。

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

表示数据流的对象。重复调用迭代器的 __next__() 方法(或将其传递给内置函数 next())会返回流中的连续项。当没有更多数据可用时,将引发 StopIteration 异常。此时,迭代器对象已用尽,对其__next__() 方法的任何进一步调用只需再次引发StopIteration。迭代器需要有一个返回迭代器对象本身的__iter__() 方法,因此每个迭代器也是可迭代的,并且可以在接受其他可迭代的大多数地方使用。一个值得注意的例外是尝试多次迭代的代码。每次将容器对象(例如列表)传递给 iter() 函数或在 for 循环中使用它时,都会生成一个新的迭代器。使用迭代器尝试此操作只会返回在前一次迭代过程中使用的相同耗尽的迭代器对象,使其看起来像一个空容器。

【讨论】:

    【解决方案2】:

    迭代器是可迭代的。 zip 返回迭代器这一事实并不意味着它不返回可迭代对象。此外,如果本书是为 Python 2 编写的,ziprange 都会返回该版本中的列表。

    【讨论】:

    • “zip 返回迭代器的事实并不意味着它不返回可迭代对象”是什么意思?顺便说一句,这本书是为 Python 3 编写的。
    • @Jin:zip 返回一个迭代器,但是这个迭代器也是一个可迭代的。这些类别不是相互排斥的;成为某一类别的成员并不意味着不成为另一类别的成员。
    【解决方案3】:

    除了其他答案,您可能会发现 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 是类,不再是函数,因此说它们“返回”某些东西可能是不准确的)

    【讨论】:

    • 谈论类返回的东西很好。类或内置函数或方法只是一个实现细节;就鸭子打字而言,如果你能调用它,它就是一个函数。
    猜你喜欢
    • 2012-08-20
    • 1970-01-01
    • 2019-06-03
    • 2015-04-08
    • 2021-07-05
    • 2016-10-27
    • 2013-06-04
    • 1970-01-01
    • 2019-02-07
    相关资源
    最近更新 更多