Python的迭代器,迭代器和迭代协议究竟是什么?

Python中“iterable”,“iterator”和“iteration”的最基本定义是什么?

我已经阅读了多个定义,但是它们的确切含义仍然不会消失。

有人可以帮助我的基本思路?

迭代是一个接一个地把每件东西都拿走的总称。 任何时候你使用循环,显式的或隐式的,遍历一组项目,这是迭代。

在Python中, iterableiterator具有特定的含义。

iterable是一个对象,它有一个返回一个迭代器__iter__方法,或者定义了一个可以从零开始的连续索引(并且在索引不再有效时引发IndexError__getitem__方法。 所以一个迭代器是一个你可以从中获取迭代器的对象。

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

无论何时在Python中使用for循环, map或列表理解等,都会自动调用next方法来从迭代器中获取每个项目,从而遍历迭代过程。

开始学习的好地方是教程的迭代器部分和标准types页面的迭代器types部分 。 在了解基础知识之后,请尝试Functional Programming HOWTO的迭代器部分 。

以下是我在Python类教学中的解释:

一个ITERABLE是:

  • 任何可以循环的东西(即你可以循环一个string或文件)或
  • 任何可以出现在for循环右边的东西: for x in iterable: ...或者
  • 任何你可以调用iter()将返回一个ITERATOR: iter(obj)
  • 一个定义返回一个新的ITERATOR的__iter__的对象,或者它可能有一个适用于索引查找的__getitem__方法。

ITERATOR是一个对象:

  • 记住迭代过程中的状态,
  • __next__方法:
    • 返回迭代中的下一个值
    • 更新状态以指向下一个值
    • 通过提高StopIteration完成信号
  • 这是自我迭代的(意味着它有一个返回self__iter__方法)。

笔记:

  • Python 3中的__next__方法是在Python 2中拼写的,而
  • 内build函数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 

上面的答案很好,但是就我所看到的大部分而言,不要强调像我这样的人的区别

另外,人们往往会通过把“X是一个具有__foo__()方法的对象”之类的定义放在“太Pythonic”之前。 这样的定义是正确的 – 它们是基于鸭子打字理念的,但是当试图以简单的方式理解概念时,对方法的关注往往会介于两者之间。

所以我添加我的版本。


在自然语言中,

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

在Python中,

  • iterable是一个可迭代的对象,简而言之,它意味着它可以在迭代中使用,例如for循环。 怎么样? 通过使用迭代器 。 我会在下面解释。

  • …而迭代器是定义如何实际进行迭代的对象 – 具体来说,下一个元素是什么 。 这就是为什么它必须有next()方法。

迭代器本身也是可迭代的,不同的是它们的__iter__()方法返回相同的对象( self ),而不pipe其之前的调用next()是否已经消耗它的项目。


那么Python解释器for x in obj: statement中看到for x in obj:什么意思?

看,一个for循环。 看起来像一个迭代器的工作…让我们得到一个。 …有这个obj人,所以让我们问他。

obj先生,你有你的迭代器吗? (…调用iter(obj) ,它调用obj.__iter__() ,它愉快地发出一个shiny的新迭代器_i 。)

好吧,那很简单…我们开始迭代吧。 ( x = _i.next()x = _i.next() …)

因为obj先生在这个testing中成功了(通过某种方法返回一个有效的迭代器),我们用形容词来奖励他:现在你可以称他为“可迭代先生obj ”。

但是,在简单的情况下,你通常不会单独使用迭代器和迭代器。 所以你定义一个对象,这也是它自己的迭代器。 (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的答案。

想象一下你可以做什么:

 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循环中用作“源”。 循环主要需要的是__iter__() (用next()返回)。

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

  • Iterator的next()可以抛出StopIteration来停止迭代。 尽pipe如此,它可以永久迭代或使用其他方法。

  • 在上述“思考过程”中, _i并不存在。 我已经制定了这个名字。

  • Python 3.x有一个小小的改变: next()方法(不是内置的)现在必须被调用__next__() 。 是的,应该一直如此。

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

免责声明:我不是任何Python解释器的开发者,所以我不知道解释器“认为”是什么。 上面的沉思仅仅是我从一个Python新手的其他解释,实验和实际经验中理解这个话题的唯一例证。

一个可迭代的对象有一个__iter__()方法。 它可以迭代多次,比如list()tuple()

迭代器是迭代的对象。 它由__iter__()方法返回,通过自己的__iter__()方法返回,并且在3.x中有next()方法( __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 

我不认为你可以比文档更简单,但我会尝试:

  • 迭代是可以迭代的东西。 在实践中,它通常意味着一个序列,例如有一个开始和结束的东西,以及通过它的所有项目的一些方法。
  • 你可以认为迭代器是一个辅助的伪方法(或伪属性),它赋予(或持有) 迭代器中的下一个(或第一个)项。 (实际上它只是一个定义next()方法的对象)

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

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

我不知道它是否对任何人有帮助,但我总是喜欢想像我脑海中的概念,以便更好地理解它们。 因此,我有一个小儿子,用砖块和白皮书来呈现iterable / iterator的概念。

假设我们在黑暗的房间里,在地上,我们为我的儿子砖。 不同大小,颜色的砖,现在无所谓。 假设我们有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列表是我们的砖套件,但不是一张白纸。 我需要先find一个迭代器:

 >>> 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 >>> 

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

 iterable = [1, 2] iterator = iter(iterable) print(iterator.__next__()) print(iterator.__next__()) 

所以,

  1. iterable是一个可以循环对象 。 例如列表,string,元组等

  2. 在我们的iterable对象上使用iter函数将返回一个迭代器对象。

  3. 现在这个迭代器对象的方法名为__next__ (在Python 3中,或者在Python 2中只是next ),通过它可以访问每个迭代元素。

所以,上面的代码将是:

1

2

在Python中,一切都是一个对象。 当一个对象被认为是可迭代的,这意味着你可以作为一个集合来遍历(即迭代)该对象。

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

字典(键/值对,也称为关联数组)也是可迭代的。 你可以通过他们的钥匙。

很明显,不是集合的对象是不可迭代的。 例如一个布尔对象只有一个值,True或False。 这是不可迭代的(这是一个可迭代的对象是没有意义的)。

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