Python的迭代器,迭代器和迭代协议究竟是什么?
Python中“iterable”,“iterator”和“iteration”的最基本定义是什么?
我已经阅读了多个定义,但是它们的确切含义仍然不会消失。
有人可以帮助我的基本思路?
迭代是一个接一个地把每件东西都拿走的总称。 任何时候你使用循环,显式的或隐式的,遍历一组项目,这是迭代。
在Python中, iterable和iterator具有特定的含义。
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__())
所以,
-
iterable
是一个可以循环的对象 。 例如列表,string,元组等 -
在我们的
iterable
对象上使用iter
函数将返回一个迭代器对象。 -
现在这个迭代器对象的方法名为
__next__
(在Python 3中,或者在Python 2中只是next
),通过它可以访问每个迭代元素。
所以,上面的代码将是:
1
2
在Python中,一切都是一个对象。 当一个对象被认为是可迭代的,这意味着你可以作为一个集合来遍历(即迭代)该对象。
数组例如是可迭代的。 您可以使用for循环遍历它们,并从索引0到索引n,n是数组对象的长度减1。
字典(键/值对,也称为关联数组)也是可迭代的。 你可以通过他们的钥匙。
很明显,不是集合的对象是不可迭代的。 例如一个布尔对象只有一个值,True或False。 这是不可迭代的(这是一个可迭代的对象是没有意义的)。