python语言之二:python迭代器
python迭代器绝对可以说是python的一种语言机制,python语言基础上一大部分就是迭代器建立起来的,所以要学习它,并搞清楚迭代器的原理。
本文从迭代器协议说起,然后介绍为何说迭代器是python语言的基础,最后介绍generator这种迭代器。
python的迭代器协议
先回忆一下常规的迭代器,C++和JAVA的迭代器是和容器紧紧结合在一起的,容器返回一个迭代器,然后就可以用iter++去访问迭代器了。为了访问容器,需要一个迭代器对象。
python迭代器在概念上没有什么不同,和经典迭代器不同比较不同的是,python迭代器不一定非要和容器结合在一起,或者说不一定要代码来实现,很多工作都是由python解释器实现的。
怎样称之为一个迭代器呢?支持python迭代器协议即可
The iterator objects themselves are required to support the following two methods, which together form the *iterator protocol*:
<dl class="method">
<dt id="iterator.__iter__">`iterator.``__iter__`()</dt>
<dd>
Return the iterator object itself. This is required to allow both containers and iterators to be used with the [`for`](../reference/compound_stmts.html#for) and [`in`](../reference/expressions.html#in) statements..
</dd>
</dl>
<dl class="method">
<dt id="iterator.__next__">`iterator.``__next__`()</dt>
<dd>
Return the next item from the container. If there are no further items, raise the [`StopIteration`].
</dd>
</dl>
这是python标准文档摘出来的,第一句话就说了,遵循迭代器协议,只要遵循这个协议,python解释器可以在for in语句支持迭代操作。
迭代器是python语言的基础
考虑一下python的循环语句,有两种循环控制,一种是for,一种是while,问题是为何要while呢?
# for语句和迭代器紧密的结合在一起,可以说就是一个紧耦合,python的解释器把for和迭代器就栓在一起了
for i in iter:
dosomething
# for搞不定的东西,例如说一直循环满足某个条件就退出
while condition:
dosomething
这里按道理来讲,所有的while应该都能用for替代,怎么替代,就是按照语言本身的机制,实现condition的迭代器。但是还是用while比较直观。
对比一下go语言就更加清楚了,go语言只有for,没有while
// 一般型,对应于python for
for init; condition;then {}
// 条件型 对应于python while
for conditon {}
// 无限循环
for {}
go节省了一个while,但是重点不是节省了while,而是对比看python怎样把for和迭代器紧耦合在一起,成为语言的机制了。
看到这里,再去学习python数据结构就比较有感觉了,随便查看一下python的复合结构list\tuple\string\set\dict,这些数据结构的操作是不是都和迭代器紧密的结合在一起呢?
例如说可以用for in语句直接访问这些复合结构,解释器讲调用迭代器,把这些复合结构转迭代器,如果留意到这点,再去学习,你会很容易的对python更加深入一步。
例如说:
l = [1,2,3,4]
for i in l:
print(i)
神奇的Generator
generator在python中,比较神奇。我用我的理解来说一下,generator是基于python堆栈技术的迭代器。也就是说这是一个两层结构,第一层是迭代器,下面那层是基于堆栈的一个特殊实现。
迭代器层
首先看下面代码:
def addOne(i):
yield (i+1)
python解释器在遇到yield关键字的时候,给它穿上迭代器的协议的新衣,在for in语句中就可以使用这个迭代器了。一个yield相当于一步next操作,注意,只是一步。
堆栈实现层
这个在segmentfault.com/a/1190000011330511中有详细的解释
由于python迭代器是个程序,运行在堆中,所以不同于c, python迭代器的堆栈也在堆中,堆栈中的调用是指向堆的,所以在遇到yield的时候,python解释器就直接生产生成器,而不是执行代码。
在这个层次,generator也有自己的操作,send,每次send就如同在操作next操作一样,所不同的是,send能传递给迭代器参数,当然第一个yield不能传递参数,第二个yield才可以。
没有详细介绍过多的generator的细节,只是想简单说明一下,不要被generator迷惑,它的本质技术不是迭代器,只是被封装的符合迭代器操作,这样更符合人的认知。更强大的是很符合人类的思考方式,可以在代码中需要的地方插入yield产生generator,符合人类的思考方式才是generator最强大之处。
总结
python的迭代器是python语言的基础,只要符合迭代器协议,python的解释器就会帮你建立迭代器。从抽象的意义上,python使用迭代器作为界面,python的各种数据结构,包括神奇的generator,都是在迭代器界面下的一种迭代器的实现。