pythonmapiter_python迭代器与解析

python迭代器与解析

迭代器初探

可能大家都已经知道for循环语句可以作用域任何序列类型,包括列表、元组以及字符串。实际上for循环能够作用于任何可迭代的对象,除了for语句,python中所有会从左至右的迭代工具都是如此,这些迭代工具包括:for循环、列表解析、in成员关系测试以及map内置函数等….

这里就涉及到很重要的一个概念-----可迭代对象,除此之外还有一个与它很类似的概念,叫做迭代对象,很多人经常分不清楚他们。迭代对象是指实现了__iter__与next方法的对象,而可迭代对象可以只实现__iter__方法,也可以两个都实现。有的可迭代对象的迭代对象就是它本身。说了那么多,不如我们直接自己实现一下:

class MyRange(object):def __init__(self, n):self.idx = 0self.n = ndef __iter__(self):return selfdef next(self):if self.idx 

上面这个类既实现了__iter__方法,也实现了next方法,并且它的__iter__方法返回了它自身,所以这个可迭代对象的的迭代对象就是它自身。上面的类其实就相当于我们python中使用的xrange函数。

for i in myRange:print i

cb3976f833f2a566084387ba4958ac80.png

这里写图片描述

如果一个可迭代对象同时它的迭代对象又是它本身的话会导致一个问题,无法重复迭代,例如:

acd2443a5e3c757acbdfc93444b0d8c0.png

从图中可以看到,当我迭代完一次过后,迭代器就被迭代完了,当我第二次用for迭代的时候没有任何输出。解决这一问题的办法就是分离迭代对象与可迭代对象。

class Zrange:def __init__(self, n):self.n = ndef __iter__(self):return ZrangeIterator(self.n)class ZrangeIterator:def __init__(self, n):self.i = 0self.n = ndef __iter__(self):return selfdef next(self):if self.i 

结果:

5e136cd6d0c17309dc05a4ef5c8b7f0b.png

这里写图片描述

注:我们可以通过iter()内建函数获取一个可迭代对象的迭代对象,然后通过is比较,例如:

c95753398ac21f6b3c8c6a515e636388.png

这里写图片描述

可以看到列表类型的迭代对象不是它本身

手动迭代:iter与next

相信通过上面的例子,大家已经很清楚迭代器的工作原理了,下面我们来通过手动迭代,更加直观的来认识迭代器。

5a67365bf58abf0f0d670af6ddaf7a72.png

查看大图可以看到,我们创建了一个a列表,这个列表中实现了__iter__方法,我们已经知道这个方法返回了一个迭代对象,我们接着看一下

07b7d209f0de76844f36033d08d5bde0.png

这里写图片描述

可以看到这个迭代对象中实现了next方法。

e525f3b5cd65b8315dd2b66a5a690e4a.png

这里写图片描述

然后我们通过手动迭代观察了一下,每调用一次next迭代器就走一步,走到头就抛出StopIteration。我们的for循环等迭代操作也就是利用了这个原理。

注:文件也是一个可迭代对象,我们可以用for循环按行遍历

列表解析初探

我们用一个例子走近列表解析的大门,加入我们想要修改一个列表,以前我们能会这么做:

1,2,3,4,5]for i in range(len(L)):10print L

但是实际上这样太麻烦了,我们完全可以偷懒,而且还可以提高运行效率(通常列表解析效率更高):

for x in L]print L

现在让我们来更详细的剖析一下这个例子:列表解析写在一个方括号中,因为他们最终是构建一个新的列表(python3.0中,可以用解析构造元组,字典等)。上面的列表解析式执行的操作就是,依次从原来的L列表中取出一个数,暂存在x变量里,然后这个x在加上10,直到遍历完整个L表,同时也就形成了一个新的列表。再来看一个例子:

'123\n','234\n']for x in a]print b

8eaa6b6b7192be5b1cfe09cc6eeb0650.png

这里写图片描述

我们对原来列表中的每一项去掉了换行符,然后组成了新的列表

生成器

刚刚我们也了解了列表解析式是什么东西,其实生成器的写法与列表解析式差不多,只是把方括号改为圆括号。例如:

for x in range(11))

这就构造了一个生成器。

fe4add03aea6a0987c950fffc7824d40.png

这里写图片描述

那到底生成器是什么东西?它有什么用呢?我们通常在写列表解析式的时候,都是表达式执行过后都会直接生成一个序列,比如:

for x in range(11)]

就会生成

1,2,3,4,5,6,7,8,9,10]

这样一个完整的序列,但是生成器表达式执行后生成的不是一个序列,而是相当于一种算法,每运行一次这个表达式都会返回序列的下一个值,这个值是现场生成的(不是一开始就保存在内存中的)。这样有什么好处,相信大家都可以想到——节约空间(也许小程序中感受不到有什么差异,但是当这个序列很大的时候就…..)实际上,生成器生成的是一个迭代对象也是一个可迭代对象。所以,其实它也有一个next方法:

4ba7b2476ce142335b69343f374b946e.png

这里写图片描述

当然,这种写法构造的生成器,实际上它能完成的功能不丰富,就像一个列表解析式一样。所以,还有另外一种写法,例如:

def fib(max):0, 0, 1while n 

上面的函数执行后会打印一串斐波那契数列。我们同样可以写成一个生成器,这只需要简单的把print改为yield。

def fib(max):0, 0, 1while n 

有了yield之后,每调用一次next方法,就会返回yield后面的值,并且不再往后执行,而是在下一次调用next方法时执行,一直重复,直到抛出StopIteration错误。

send与close方法

这两个方法也是与生成器相关的,但是感觉用的不太多,就不详细介绍了。

这里写图片描述热爱python与web安全

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值