Python迭代器

迭代器是python中很重要的一个概念,本节主要让大家可以回答下面几个问题:

1.迭代(iterate)是什么?2.可迭代对象(iterable)是什么3.迭代器(iterator)是什么?4.如何自定义一个迭代器?5.迭代对象与迭代器的关系是什么?

迭代 iterate

在其他编程语言中,比如java、c,我们喜欢将通过while或for关键字实现的重复行为称为循环(loop),但是在python中,只能通过while来实现循环,而for用于实现迭代(iterate),它的结构搭建应该很熟悉,就是for ... in ...,那循环和迭代在定义上有什么差别呢?

循环(loop),指的是在满足条件的情况下,重复执行同一段代码。比如 Python 中的 while 语句。迭代(iterate),指的是按照某种顺序逐个访问列表中的每一项。比如 Python 中的 for 语句。

在python中,可以使用for关键字逐个访问可迭代对象

可迭代对象 iterable

在python中,任意对象只要定义了_iter方法或者定义了可以支持下标索引的getitem_方法,它就是一个可迭代对象,很清晰,可以通过python内置的dir函数来查看某个对象是否定义了iter方法或getitem方法

比如看看list类型是否是可迭代对象

从上面可以看出list中既有iter方法又有getitem方法,符号经验,因为list可以通过for关键字迭代,也可以通过下标访问list中具体的元素,那么就可以说list是可迭代对象

同理,通过dir函数查看一下str字符串类型

可以看出str同样具有iter方法和getitem方法,依旧符号经验,str类型同样可以使用for来迭代,也可以通过下标来获得其中的值,str也是可迭代对象。

处了这些,在python中还有很多对象是可迭代对象,比如打开状态下的文件流files、网络流sockets等等

迭代器 iterator

在python中,任何对象只要定义了_iter方法和next_方法,它就是一个迭代器,这里有几个信息点需要注意。

1.迭代器一定是可迭代对象,因为迭代器需要有iter方法,而只要有iter方法就可以认为对象是可迭代对象2.迭代器比可迭代对象一般多实现了一个next方法,一般这个词很重要,因为有例外情况,就是可迭代对象没有定义iter方法,只定义了getitem方法的情况

举个例子,理解一下,通过上面的介绍,我们已经知道了str字符串类型是可迭代对象,那么它是否是迭代器呢?我们可以同样可以通过dir函数来看str类型中是否定义了next方法,或者直接调用next()函数,看看是否会报错

使用str类型的对象调用next()会报错,报错信息说str不是一个iterator迭代器,很明显,str类型没有定义next方法,它是一个可迭代对象,但却不是一个迭代器

同理,list也一样,list是一个可迭代对象,但却不是一个迭代器

我们可以通过python内置的iter()方法将一个可迭代对象转换成一个迭代器,这样就可以使用next()方法了

使用iter()方法的世界执行情况可以通过下图直观理解

可以看出,如果每次要从迭代器中获取下一个元素都要使用next()方法话,人都傻了,所以我们一般使用for来获得迭代器中的内容,那么问题就来了,可迭代对象本身就可以通过for来迭代从而获得其中的值,为何还要转换为迭代器?这样一看,迭代器多个next方法似乎也没什么用。

为了理解这个问题,可以使用for来迭代一下可迭代对象s和迭代器ss,这两个对象在上面代码中都已经定义好了,s='ayuliao',而ss=iter(s)

可以看出,迭代器使用for迭代出来的内容少了ayuliao的开头字母a,这是因为在迭代器在使用for迭代前,已经通过next()方法获取了字母a,再次通过for来迭代也只能获取迭代器中剩余的内容,也就是'yuliao',这表明,迭代器中的所有元素都只能取一次

如果迭代器中已经没有内容了,还调用next()方法去获取下一个值,next()方法则会报StopIteration异常

同样通过for迭代已经没有内容的迭代器,也获取不了任何内容,因为for处理了StopIteration异常的情况,所以不会有异常抛出

在python中其实有很多方法都返回迭代器,最为人知的就是itertools库下的函数大部分都返回迭代器对象

可以通过itertools下的count生成一个无限序列,可以从开始数值到无穷大,返回的是迭代器对象

还可以通过itertools下的cycle生成一个无限循环序列,返回的是迭代器对象

自定义迭代器

已经知道了迭代器就是定义了iter方法和next方法的对象,那么自定义迭代器就很简单了,在自定义对象中定义iter方法和next方法就好了

这里定义一个迭代器,用于获得斐波那契数列,所谓斐波那契数列就是符合前两个数相加等于第三个数的数列,如1,1,2,3,5,8...

在代码中,声明了Fib类,该类中定义了iter方法和next方法,因为定义了这两个方法,所以Fib类是迭代器,因为Fib类会生成一个无限的斐波那契数列,所以使用了islice方法限制其只获取前20个数,代码运行效果如下

每次运行next()方法获取迭代器中下一次的值时,next()方法主要做了两件事:

1.返回此次调用next()方法生成的返回结果2.为下一次调用next()方法修改状态

当然实现一个斐波那契数列其实根本就不需要动用迭代器,设计一下,一个简单循环就可以了,那为何还要有迭代器呢?因为使用迭代器省内存,如果你需要打印前1000万个斐波那契数,单纯的使用循环就需要将这1000万的值都要存到内存中,会消耗大量的内容,如果使用迭代器就不会出现内存大量消耗的情况,迭代器很懒很健忘,它只有在你需要什么值的时候才执行函数内的逻辑,返回相应的值,然后就将它忘了,这样就几乎不怎么耗内存了。

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180313G1SVUM00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

同媒体快讯

扫码关注云+社区

领取腾讯云代金券