ChatGPT解决这个技术问题 Extra ChatGPT

什么是迭代器、可迭代和迭代?

Python中的“可迭代”、“迭代器”和“迭代”是什么?它们是如何定义的?

希望对您有所帮助:towardsdatascience.com/…

B
Bryan

迭代是一个通用术语,用于一个接一个地获取某物的每一项。每当您使用循环(显式或隐式)来遍历一组项目时,这就是迭代。

在 Python 中,iterable 和 iterator 具有特定的含义。

iterable 是具有 __iter__ 方法的对象,该方法返回 iterator,或者定义了可以从零开始获取顺序索引的 __getitem__ 方法(并引发IndexError 当索引不再有效时)。所以 iterable 是一个可以从中获取 iterator 的对象。

iterator 是具有 next (Python 2) 或 __next__ (Python 3) 方法的对象。

每当您在 Python 中使用 for 循环、map 或列表解析等时,都会自动调用 next 方法以从 iterator 中获取每个项目,从而通过迭代的过程。

iterators section of the tutorialiterator types section of the standard types page 是开始学习的好地方。了解基础知识后,请尝试 iterators section of the Functional Programming HOWTO


请注意,collections.abc.AsyncIterator 测试 __aiter____anext__ 方法。这是 3.6 中的新增功能。
@jlh 为什么 __len__ 必然与迭代相关联?知道某物的长度如何帮助您迭代它?
@shadowtalker 有助于了解哪些索引是有效的,因此您知道哪些索引可以与 __getitem__ 一起使用。
@jlh 听起来您提出了一种非常自以为是的 dfeault 行为。考虑 {'a': 'hi', 'b': 'bye'} 的长度为 2,但不能被 0、1 或 2 索引。
@shadowtalker。但是 dict 有一个 __iter__ 方法。我认为 jlh 指的是特别是可迭代的对象,因为它们定义了:“可以采用从零开始的顺序索引的 __getitem__ 方法”。
M
Mateen Ulhaq

这是我在教授 Python 课程时使用的解释:

一个 ITERABLE 是:

可以循环的任何内容(即您可以循环字符串或文件)或

任何可以出现在 for 循环右侧的东西:for x in iterable: ... 或

你可以用 iter() 调用的任何东西都会返回一个 ITERATOR: iter(obj) 或

定义 __iter__ 的对象,该对象返回一个新的 ITERATOR,或者它可能具有适合索引查找的 __getitem__ 方法。

一个 ITERATOR 是一个对象:

在迭代期间记住它在哪里的状态,

使用 __next__ 方法:返回迭代中的下一个值 更新状态以指向下一个值信号,当它通过引发 StopIteration 完成时

返回迭代中的下一个值

更新状态以指向下一个值

通过引发 StopIteration 完成时发出信号

那是自迭代的(这意味着它有一个返回 self 的 __iter__ 方法)。

笔记:

Python 3 中的 __next__ 方法在 Python 2 中拼写为 next,并且

内置函数 next() 在传递给它的对象上调用该方法。

例如:

>>> s = 'cat'      # s is an ITERABLE
                   # s is a str object that is immutable
                   # s has no state
                   # s has a __getitem__() method 

>>> t = iter(s)    # t is an ITERATOR
                   # t has state (it starts by pointing at the "c"
                   # t has a next() method and an __iter__() method

>>> next(t)        # the next() function returns the next value and advances the state
'c'
>>> next(t)        # the next() function returns the next value and advances
'a'
>>> next(t)        # the next() function returns the next value and advances
't'
>>> next(t)        # next() raises StopIteration to signal that iteration is complete
Traceback (most recent call last):
...
StopIteration

>>> iter(t) is t   # the iterator is self-iterable

新鲜迭代器是什么意思?
@lmiguelvargasf “新鲜”,如“新的和未消费的”,而不是“用尽或部分消费”。这个想法是一个新的迭代器从头开始,而一个部分使用的迭代器从它停止的地方开始。
您的第二个、第三个和第四个项目符号清楚地表明了您的意思,就特定的 python 构造或内置函数或方法调用而言。但是第一个项目符号(“任何可以循环的东西”)没有那么清晰。此外,第一个项目符号似乎与第二个项目符号重叠,因为第二个项目符号大约是 for 个循环,而第一个项目符号是关于“循环”。你能解决这些问题吗?
请考虑将“您可以使用 iter() 调用的任何内容”重新表述为“您可以传递给 iter() 的任何内容”
没有 __iter__() 方法的可迭代示例是什么? (只有一个 __getitem__()?)
C
Community

上面的答案很好,但正如我所看到的那样,对于像我这样的人来说,不要强调足够的区别。

此外,人们往往会通过将“X 是具有 __foo__() 方法的对象”之类的定义放在前面来获得“太 Pythonic”。这样的定义是正确的——它们是基于鸭式的哲学,但是在试图理解简单的概念时,对方法的关注往往会介于两者之间。

所以我添加了我的版本。

在自然语言中,

迭代是在一行元素中一次取一个元素的过程。

在 Python 中,

iterable 是一个可以迭代的对象,简单地说,它意味着它可以在迭代中使用,例如使用 for 循环。如何?通过使用迭代器。我会在下面解释。

...而迭代器是一个对象,它定义了如何实际进行迭代——特别是下一个元素是什么。这就是为什么它必须有 next() 方法。

迭代器本身也是可迭代的,区别在于它们的 __iter__() 方法返回相同的对象 (self),无论其项目是否已被先前对 next() 的调用使用。

那么 Python 解释器在看到 for x in obj: 语句时会怎么想呢?

看,一个for循环。看起来像是迭代器的工作......让我们来做一个。 ......有这个obj家伙,所以让我们问他。 “obj先生,你有你的迭代器吗?” (...调用 iter(obj),它调用 obj.__iter__(),它愉快地分发了一个闪亮的新迭代器 _i。)好的,这很容易......让我们开始迭代。 (x = _i.next() ... x = _i.next()...)

由于 obj 先生在此测试中成功(通过让某些方法返回有效的迭代器),我们用形容词奖励他:您现在可以称他为“可迭代的 obj 先生”。

但是,在简单的情况下,您通常不会从分别拥有 iterator 和 iterable 中受益。所以你定义只有一个对象,它也是它自己的迭代器。 (Python 并不真正关心 obj 分发的 _i 不是那么闪亮,而只是 obj 本身。)

这就是为什么在我见过的大多数示例中(以及一遍又一遍让我感到困惑的地方),你可以看到:

class IterableExample(object):

    def __iter__(self):
        return self

    def next(self):
        pass

代替

class Iterator(object):
    def next(self):
        pass

class Iterable(object):
    def __iter__(self):
        return Iterator()

但是,在某些情况下,您可以从将迭代器与可迭代对象分离中受益,例如当您希望拥有一行项目但有更多“游标”时。例如,当您想使用“当前”和“即将到来的”元素时,您可以为这两个元素设置单独的迭代器。或者从一个巨大的列表中提取多个线程:每个线程都可以有自己的迭代器来遍历所有项目。请参阅上面的 @Raymond's@glglgl's 答案。

想象一下你能做什么:

class SmartIterableExample(object):

    def create_iterator(self):
        # An amazingly powerful yet simple way to create arbitrary
        # iterator, utilizing object state (or not, if you are fan
        # of functional), magic and nuclear waste--no kittens hurt.
        pass    # don't forget to add the next() method

    def __iter__(self):
        return self.create_iterator()

笔记:

我再重复一遍:迭代器是不可迭代的。迭代器不能用作 for 循环中的“源”。 for 循环主要需要的是 __iter__() (用 next() 返回一些东西)。

当然, for 不是唯一的迭代循环,所以上面也适用于其他一些构造(while...)。

迭代器的 next() 可以抛出 StopIteration 来停止迭代。但是,它可以永远迭代或使用其他方式。

在上面的“思考过程”中,_i 并不真正存在。这个名字是我编的。

Python 3.x 有一个小的变化:next() 方法(不是内置的)现在必须称为 __next__()。是的,应该一直都是这样。

也可以这样想:iterable 有数据,iterator 拉下一项

免责声明:我不是任何 Python 解释器的开发人员,所以我真的不知道解释器的“想法”。上面的思考只是展示了我如何从 Python 新手的其他解释、实验和现实生活中理解这个话题。


这很棒——但我还是有点困惑。我以为你的黄色框是在说 for 循环需要一个迭代器(“看,一个 for 循环。看起来像一个迭代器的工作......让我们得到一个。”)。但是你在最后的注释中说“迭代器不能用作for循环中的源”......?
为什么您只将 pass 放入那些 next 定义的代码中?我假设你只是意味着有人必须实现一种方法来获取下一个,因为 next 必须返回一些东西。
@nealmcb 是的,我认为这就是我过去的意思。 (毕竟,这就是 pass is for。)
@AloisMahdal 啊,我以前没见过这种用法。当我看到 pass 时,我认为它是出于句法原因。我刚刚在 ellipsis object 遇到了非常有趣的答案:您可以使用 ... 来表示“待办事项”块。 NotImplemented 也可用。
虽然我喜欢你强调迭代器和可迭代之间的区别,但这个答案自相矛盾。首先,您编写“迭代器本身也是可迭代的”(与 the Python documentation 中的内容相匹配)。但后来你写:'iterator is not iterable。迭代器不能用作 for 循环中的“源”。我明白你的回答的重点,并且喜欢它,但我认为它会从解决这个问题中受益。
g
glglgl

可迭代对象是具有 __iter__() 方法的对象。它可能会迭代多次,例如 list()tuple()

迭代器是迭代的对象。它由 __iter__() 方法返回,通过其自己的 __iter__() 方法返回自身并具有 next() 方法(3.x 中的 __next__())。

迭代是调用这个 next() 的过程。 __next__() 直到它引发 StopIteration

例子:

>>> a = [1, 2, 3] # iterable
>>> b1 = iter(a) # iterator 1
>>> b2 = iter(a) # iterator 2, independent of b1
>>> next(b1)
1
>>> next(b1)
2
>>> next(b2) # start over, as it is the first call to b2
1
>>> next(b1)
3
>>> next(b1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> b1 = iter(a) # new one, start over
>>> next(b1)
1

所以真的它只是一个通过容器的对象吗?这会有用吗?
经常,但并非总是如此。生成器、文件或数据库游标只能迭代一次,因此是它们自己的迭代器。
我猜 b2 不必独立于 b1 ?对于这种特殊情况,它是独立的,当然我可以让它不是独立的,但也是一个有效的 Iterable
@PatrickT 所有三个:是的。试试看。 for i in [1,3,4,6]: print(i) / for i in {1,3,4,6}: print(i) / for i in (1,3,4,6): print(i)。另外,请查看文档。语言规范。
@PatrickT 这甚至可能取决于 Python 版本和执行历史(例如对象 ID/地址、它们的类型等)。如果您需要对集合进行排序,请参阅 this question 中有关有序集合的更多信息。
A
AXO

这是我的备忘单:

 sequence
  +
  |
  v
   def __getitem__(self, index: int):
  +    ...
  |    raise IndexError
  |
  |
  |              def __iter__(self):
  |             +     ...
  |             |     return <iterator>
  |             |
  |             |
  +--> or <-----+        def __next__(self):
       +        |       +    ...
       |        |       |    raise StopIteration
       v        |       |
    iterable    |       |
           +    |       |
           |    |       v
           |    +----> and +-------> iterator
           |                               ^
           v                               |
   iter(<iterable>) +----------------------+
                                           |
   def generator():                        |
  +    yield 1                             |
  |                 generator_expression +-+
  |                                        |
  +-> generator() +-> generator_iterator +-+

测验:你知道如何...

每个迭代器都是可迭代的?容器对象的 __iter__() 方法可以实现为生成器吗?具有 __next__ 方法的迭代器不一定是迭代器?

答案:

每个迭代器都必须有一个 __iter__ 方法。拥有 __iter__ 就足以成为可迭代对象。因此,每个迭代器都是可迭代的。当 __iter__ 被调用时,它应该返回一个迭代器(在上图中返回 )。调用生成器会返回一个生成器迭代器,它是一种迭代器。 class Iterable1: def __iter__(self): # 一个方法(定义在类体内的函数) # 调用 iter() 将 iterable (tuple) 转换为 iterator return iter((1,2,3)) class Iterable2: def __iter__(self): # a generator for i in (1, 2, 3): yield i class Iterable3: def __iter__(self): # with PEP 380 syntax yield from (1, 2, 3) # 传递断言 list(Iterable1 ()) == list(Iterable2()) == list(Iterable3()) == [1, 2, 3] 下面是一个例子: class MyIterable: def __init__(self): self.n = 0 def __getitem__( self, index: int): return (1, 2, 3)[index] def __next__(self): n = self.n = self.n + 1 if n > 3: raise StopIteration return n # 如果可以迭代如果不引发 TypeError,那么它就是一个可迭代的。 iter(MyIterable()) # 但显然 `MyIterable()` 不是迭代器,因为它没有 # `__iter__` 方法。 from collections.abc import Iterator assert isinstance(MyIterable(), Iterator) # AssertionError


在测验中,我只理解了第一个要点。即迭代器成为一个可迭代的,因为它有 __iter__ 方法。您能否通过编辑此答案详细说明第二点和第三点
@AnV:据我了解:re 2.: __iter__() 返回一个迭代器。生成器是一个迭代器,因此可以用于此目的。 re 3.:我只能在这里猜测,但我认为如果缺少 __iter__(),或者不返回 self,它就不是迭代器,因为迭代器的 __iter__() 必须返回 self
有趣的是 isinstance(MyIterable(), collections.abc.Iterable) 也是 False。 @_@
N
Nikolay Dudaev

我不知道它是否对任何人有帮助,但我总是喜欢在脑海中形象化概念以更好地理解它们。因此,当我有一个小儿子时,我用砖块和白皮书将可迭代/迭代器概念可视化。

假设我们在黑暗的房间里,地板上有我儿子的砖块。不同大小、颜色的砖块,现在都无所谓了。假设我们有 5 块这样的砖块。这 5 块积木可以描述为一个对象——比如说积木套件。我们可以用这个积木套件做很多事情——可以拿一个然后拿第二个然后第三个,可以改变积木的位置,把第一块积木放在第二块上面。我们可以用这些做很多事情。因此,这个积木工具包是一个可迭代的对象或序列,因为我们可以遍历每块积木并对其进行处理。我们只能像我的小儿子那样做——我们一次只能玩一块砖。所以我再次想象自己这个积木套件是一个可迭代的。

现在请记住,我们在黑暗的房间里。或者几乎是黑暗的。问题是我们没有清楚地看到这些砖块,它们是什么颜色,什么形状等。所以即使我们想对它们做点什么——也就是遍历它们——我们并不真正知道是什么以及如何做,因为它是太暗了。

我们可以做的是靠近第一个砖块——作为砖块套件的元素——我们可以放一张白色荧光纸,以便我们看到第一个砖块元素在哪里。每次我们从套件中取出一块砖,我们将白纸替换为下一块砖,以便能够在黑暗的房间中看到它。这张白纸只不过是一个迭代器。它也是一个对象。但是一个我们可以使用我们可迭代对象的元素工作和玩耍的对象 - 积木套件。

顺便说一句,这解释了我在 IDLE 中尝试以下操作并得到 TypeError 时的早期错误:

 >>> X = [1,2,3,4,5]
 >>> next(X)
 Traceback (most recent call last):
    File "<pyshell#19>", line 1, in <module>
      next(X)
 TypeError: 'list' object is not an iterator

这里的清单 X 是我们的积木套件,但不是一张白纸。我需要先找到一个迭代器:

>>> X = [1,2,3,4,5]
>>> bricks_kit = [1,2,3,4,5]
>>> white_piece_of_paper = iter(bricks_kit)
>>> next(white_piece_of_paper)
1
>>> next(white_piece_of_paper)
2
>>>

不知道它是否有帮助,但它帮助了我。如果有人可以确认/纠正这个概念的可视化,我将不胜感激。这将帮助我了解更多。


K
Kimvais

我认为您不能比 documentation 简单得多,但是我会尝试:

可迭代是可以迭代的东西。在实践中,它通常意味着一个序列,例如具有开始和结束的东西,以及通过某种方式遍历其中的所有项目。

您可以将 Iterator 视为一个辅助伪方法(或伪属性),它提供(或保存)可迭代对象中的下一个(或第一个)项目。 (实际上它只是一个定义方法 next() 的对象)

迭代可能最好用 Merriam-Webster 对这个词的定义来解释:

b :重复计算机指令序列指定的次数或直到满足条件 - 比较递归


V
Vicrobot

Iterable:- 可迭代的东西就是可迭代的;像列表、字符串等序列。它也有 __getitem__ 方法或 __iter__ 方法。现在,如果我们在该对象上使用 iter() 函数,我们将获得一个迭代器。

Iterator:- 当我们从 iter() 函数中获取迭代器对象时;我们调用 __next__() 方法(在 python3 中)或简单地调用 next()(在 python2 中)来逐个获取元素。此类或此类的实例称为迭代器。

来自文档:-

迭代器的使用遍及并统一了 Python。在幕后, for 语句调用 iter() 容器对象。该函数返回一个迭代器对象,该对象定义方法 __next__() 一次访问容器中的元素。当没有更多元素时, __next__() 引发一个 StopIteration 异常,告诉 for 循环终止。您可以使用 next() 内置函数调用 __next__() 方法;这个例子展示了它是如何工作的:

>>> s = 'abc'
>>> it = iter(s)
>>> it
<iterator object at 0x00A1DB50>
>>> next(it)
'a'
>>> next(it)
'b'
>>> next(it)
'c'
>>> next(it)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
    next(it)
StopIteration

前一类:-

class Reverse:
    """Iterator for looping over a sequence backwards."""
    def __init__(self, data):
        self.data = data
        self.index = len(data)
    def __iter__(self):
        return self
    def __next__(self):
        if self.index == 0:
            raise StopIteration
        self.index = self.index - 1
        return self.data[self.index]


>>> rev = Reverse('spam')
>>> iter(rev)
<__main__.Reverse object at 0x00A1DB50>
>>> for char in rev:
...     print(char)
...
m
a
p
s

C
Community

Iterables 有一个 __iter__ 方法,每次都实例化一个新的迭代器。迭代器实现了一个返回单个项目的 __next__ 方法和一个返回 self 的 __iter__ 方法。因此,迭代器也是可迭代的,但可迭代的不是迭代器。

Luciano Ramalho,流利的 Python。


Y
Yilmaz

迭代器是实现 iter 和 next 方法的对象。如果定义了这些方法,我们可以使用 for 循环或理解。

class Squares:
    def __init__(self, length):
        self.length = length
        self.i = 0
        
    def __iter__(self):
        print('calling __iter__') # this will be called first and only once
        return self
    
    def __next__(self): 
        print('calling __next__') # this will be called for each iteration
        if self.i >= self.length:
            raise StopIteration
        else:
            result = self.i ** 2
            self.i += 1
            return result

迭代器会耗尽。这意味着在您迭代项目之后,您不能重复,您必须创建一个新对象。假设您有一个类,其中包含城市属性并且您想要迭代。

class Cities:
    def __init__(self):
        self._cities = ['Brooklyn', 'Manhattan', 'Prag', 'Madrid', 'London']
        self._index = 0
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self._index >= len(self._cities):
            raise StopIteration
        else:
            item = self._cities[self._index]
            self._index += 1
            return item

Cities 类的实例是一个迭代器。但是,如果您想重复城市,则必须创建一个新对象,这是一项昂贵的操作。您可以将该类分为 2 个类:一个返回城市,第二个返回一个迭代器,该迭代器将城市作为初始参数。

class Cities:
    def __init__(self):
        self._cities = ['New York', 'Newark', 'Istanbul', 'London']        
    def __len__(self):
        return len(self._cities)



class CityIterator:
    def __init__(self, city_obj):
        # cities is an instance of Cities
        self._city_obj = city_obj
        self._index = 0
        
    def __iter__(self):
        return self
    
    def __next__(self):
        if self._index >= len(self._city_obj):
            raise StopIteration
        else:
            item = self._city_obj._cities[self._index]
            self._index += 1
            return item

现在如果我们需要创建一个新的迭代器,我们不必再次创建数据,即城市。我们创建城市对象并将其传递给迭代器。但我们仍在做额外的工作。我们可以通过只创建一个类来实现这一点。

Iterable 是一个 Python 对象,它实现了 iterable 协议。它只需要返回迭代器对象的新实例的 __iter__()

class Cities:
    def __init__(self):
        self._cities = ['New York', 'Newark', 'Istanbul', 'Paris']
        
    def __len__(self):
        return len(self._cities)
    
    def __iter__(self):
        return self.CityIterator(self)
    
    class CityIterator:
        def __init__(self, city_obj):
            self._city_obj = city_obj
            self._index = 0

        def __iter__(self):
            return self

        def __next__(self):
            if self._index >= len(self._city_obj):
                raise StopIteration
            else:
                item = self._city_obj._cities[self._index]
                self._index += 1
                return item

Iterators 有 __iter____next__,iterables 有 __iter__,所以我们可以说 Iterators 也是 iterables,但它们是会耗尽的 iterables。另一方面,可迭代对象永远不会耗尽,因为它们总是返回一个新的迭代器,然后用于迭代

您注意到可迭代代码的主要部分在迭代器中,而可迭代本身只不过是一个额外的层,它允许我们创建和访问迭代器。

迭代一个可迭代对象

Python 有一个调用 __iter__() 的内置函数 iter()。当我们迭代一个可迭代对象时,Python 调用返回一个迭代器的 iter(),然后它开始使用迭代器的 __next__() 来迭代数据。

请注意,在上面的示例中,Cities 创建了一个可迭代但它不是序列类型,这意味着我们无法通过索引获取城市。要解决此问题,我们只需将 __get_item__ 添加到 Cities 类。

class Cities:
    def __init__(self):
        self._cities = ['New York', 'Newark', 'Budapest', 'Newcastle']
        
    def __len__(self):
        return len(self._cities)
    
    def __getitem__(self, s): # now a sequence type
        return self._cities[s]
    
    def __iter__(self):
        return self.CityIterator(self)
    
    class CityIterator:
        def __init__(self, city_obj):
            self._city_obj = city_obj
            self._index = 0

        def __iter__(self):
            return self

        def __next__(self):
            if self._index >= len(self._city_obj):
                raise StopIteration
            else:
                item = self._city_obj._cities[self._index]
                self._index += 1
                return item

A
Anentropic
iterable = [1, 2] 

iterator = iter(iterable)

print(iterator.__next__())   

print(iterator.__next__())   

所以,

iterable 是一个可以循环的对象。例如 list , string , tuple 等在我们的可迭代对象上使用 iter 函数将返回一个迭代器对象。现在这个迭代器对象有一个名为 __next__ 的方法(在 Python 3 中,或者只是在 Python 2 中的 next),您可以通过它访问 iterable 的每个元素。

因此,上述代码的输出将是:

1

2


I
Ileana Vasquez

可迭代对象是具有返回迭代器的 iter() 方法的对象。这是可以循环的东西。示例:列表是可迭代的,因为我们可以遍历列表但不是迭代器

迭代器是可以从中获取迭代器的对象。它是一个具有状态的对象,以便在迭代期间记住它的位置

要查看对象是否具有此方法 iter(),我们可以使用以下函数。

ls = ['hello','bye']
print(dir(ls))

输出

['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']

如您所见, iter() 意味着它是一个可迭代对象,但不包含作为迭代器对象特征的 next() 方法

每当您在 Python 中使用 for 循环或映射或列表推导时,都会自动调用 next 方法以从迭代中获取每个项目


A
AnV

在处理迭代器和迭代器之前,决定迭代器和迭代器的主要因素是序列

序列:序列是数据的集合

Iterable:Iterable是支持__iter__方法的序列类型对象。

Iter 方法:Iter 方法将序列作为输入并创建一个称为迭代器的对象

迭代器:迭代器是调用下一个方法并横穿序列的对象。在调用下一个方法时,它返回当前遍历的对象。

例子:

x=[1,2,3,4]

x 是一个由数据集合组成的序列

y=iter(x)

在调用 iter(x) 时,它仅在 x 对象具有 iter 方法时返回一个迭代器,否则它会引发异常。如果它返回迭代器,则 y 的赋值如下:

y=[1,2,3,4]

由于 y 是一个迭代器,因此它支持 next() 方法

在调用 next 方法时,它会一个一个地返回列表中的各个元素。

在返回序列的最后一个元素后,如果我们再次调用 next 方法,它会引发 StopIteration 错误

例子:

>>> y.next()
1
>>> y.next()
2
>>> y.next()
3
>>> y.next()
4
>>> y.next()
StopIteration

只是一个观察: y=iter(x) 不完全是 y=[1,2,3,4] 因为 y 现在是一个迭代器对象。也许您应该添加注释以澄清不是列表而是迭代器对象或更改表示。
M
MarianD

其他人已经全面解释了,什么是可迭代和迭代器,所以我将尝试对生成器做同样的事情。

恕我直言,理解生成器的主要问题是“生成器”这个词的使用令人困惑,因为这个词有两种不同的含义:

作为用于创建(生成)迭代器的工具,以函数的形式返回迭代器(即在其主体中带有 yield 语句),以生成器表达式的形式作为使用该工具的结果,即生成的迭代器。 (在这个意义上,生成器是迭代器的一种特殊形式——“生成器”这个词指出了这个迭代器是如何创建的。)

生成器作为第一类工具:

In[2]: def my_generator():
  ...:     yield 100
  ...:     yield 200

In[3]: my_generator

Out[3]: <函数 __main__.my_generator()>

In[4]: type(my_generator)

Out[4]:函数

作为一个结果生成器(即一个迭代器)使用了这个工具:

In[5]: my_iterator = my_generator()
In[6]: my_iterator

Out[6]:

In[7]: type(my_iterator)

Out[7]:生成器

生成器作为第二类工具——与该工具生成的迭代器没有区别:

In[8]: my_gen_expression = (2 * i for i in (10, 20))
In[9]: my_gen_expression

Out[9]: at 0x000000000542C048>

In[10]: type(my_gen_expression)

Out[10]:生成器


u
user650654

这是使用 collections.abc 的另一个视图。此视图可能在第二次或更晚时有用。

collections.abc 我们可以看到以下层次结构:

builtins.object
    Iterable
        Iterator
            Generator

即Generator 派生自Iterator 派生自Iterable 派生自基础对象。

因此,

每个迭代器都是可迭代的,但不是每个可迭代的都是迭代器。例如, [1, 2, 3] 和 range(10) 是可迭代的,但不是迭代器。 x = iter([1, 2, 3]) 是一个迭代器和一个可迭代对象。

Iterator 和 Generator 之间也存在类似的关系。

在迭代器或生成器上调用 iter() 会返回自身。因此,如果它是一个迭代器,那么 iter(it) is 它就是 True。

在幕后,像 [2 * x for x in nums] 这样的列表推导式或像 for x in nums: 这样的 for 循环,就像在可迭代对象 (nums) 上调用 iter(),然后使用该迭代器迭代 nums .因此,以下所有内容在功能上都是等效的(例如,nums=[1, 2, 3]): for x in nums: for x in iter(nums): for x in iter(iter(nums)): for x in iter(iter(iter(iter(iter(nums))))):

对于 nums 中的 x:

对于 iter(nums) 中的 x:

对于 iter(iter(nums)) 中的 x:

对于 x in iter(iter(iter(iter(iter(nums))))):


t
tyrex

对我来说,Python 的 glossery 对这些问题最有帮助,例如对于 iterable 它说:

一个能够一次返回其成员的对象。可迭代对象的示例包括所有序列类型(例如 list、str 和 tuple)和一些非序列类型,例如 dict、文件对象以及您使用 iter() 方法或 getitem() 方法定义的任何类的对象实现序列语义。

Iterables 可用于 for 循环和许多其他需要序列的地方(zip()、map()、...)。当可迭代对象作为参数传递给内置函数 iter() 时,它会返回该对象的迭代器。此迭代器适用于遍历一组值。使用迭代器时,通常不需要调用 iter() 或自己处理迭代器对象。 for 语句会自动为您执行此操作,创建一个临时的未命名变量以在循环期间保存迭代器。另请参见迭代器、序列和生成器。


u
user93097373

在 Python 中,一切都是对象。当一个对象被称为可迭代时,这意味着您可以将对象作为一个集合单步执行(即迭代)。

例如数组是可迭代的。您可以使用 for 循环逐步遍历它们,然后从索引 0 转到索引 n,n 是数组对象的长度减 1。

字典(键/值对,也称为关联数组)也是可迭代的。您可以逐步查看他们的密钥。

显然,不是集合的对象是不可迭代的。例如,一个 bool 对象只有一个值,True 或 False。它是不可迭代的(它是一个可迭代的对象是没有意义的)。

阅读更多。 http://www.lepus.org.uk/ref/companion/Iterator.xml


不是集合的对象是不可迭代的 通常不是真的。举几个例子,生成器是可迭代的,但不是集合,通过在标准集合类型上调用 iter() 创建的迭代器对象是可迭代的,但它们本身不是集合。