python迭代器生成器_Python中的迭代器与生成器

container.__iter__()  和 iterator.__next__()

迭代器就是一个有 __next__() 方法的对象。当需要下一个数据时,调用它的 __next__() 方法就可以获得。在Python2中,这个方法被命名为 next() 。但在Python3中新增加了内建的 next() 函数,就像用来调用 __iter__() 的 iter() 函数一样,next() 也是用来调用 __next__() 的。

就如上面所说,对迭代器来讲,有一个__next__()就够了。在你使用for 和 in 语句时,如果可行,程序就会自动调用即将被处理的对象的迭代器对象,然后使用它的__next__()方法,直到监测到一个StopIteration异常。以比较常用的 range() 来举例:

>>> type(range(10))

>>> next(range(10))

Traceback (most recent call last):

File "", line 1, in

next(range(10))

TypeError: 'range' object is not an iterator

>>> type(iter(range(10)))

>>> next(iter(range(10)))

0

我们可以看到,range(10) 本身作为一个 对象是不可迭代的,但是 iter(range(10)) 或者说 range(10).__iter__() 可以,它的类(型)是,它有 __next__() 方法。那么如何使用迭代器看起来就变得简单了——我们只要在类里面定义一个 __iter__() 函数,用它来返回一个带 __next__() 方法的对象就够了。其实按照官方文档的说法,迭代器对象里也应该有一个 __iter__() 方法,这个方法只需要一个语句 return self ,这是为了保证在使用 for 语句时,容器对象和迭代器对象都可以被正确调用,就像下面这样:

>>>for x in container:pass

>>>for x in iter(container):pass

__iter__() 的设计非常简单,因为我们大可以把 self 返回,然后在类里面定义 __next__() 。这样定义的一个类,其自身既是容器,又是迭代器(真棒)。那么接下来的主要问题就是设计 __next__() 了。

我们使用斐波那契数列来举例:

class Feb:

def __init__(self):

self.pre = 1

self.num = 0

def __iter__(self):

return self

def __next__(self):

if self.num < 10:

self.pre,self.num = self.num,self.pre+self.num

return self.num

else:raise StopIteration

试运行如下:

>>> feb = Feb()

>>> for i in feb:

print(i)

1

1

2

3

5

8

13

>>>

嗯,还算正常。for 循环正确迭代了 Feb 实例,正确处理了 StopIteration 异常。只是有一个小Bug,我本来没想让它输出13来着…

我们可以看到这个 __next__() 实现的不很好,它看起来很麻烦。那么如何“优雅”地实现迭代器呢?当然就是用“生成器”啦!

generator.__next__() 和 generator.send() 和 generator.close()

生成器是一个特定的“函数”,当调用时它返回一个生成器对象(所以你不能在定义生成器的时候 return 任何值,但可以使用单独的一个 return ,它代表进度结束)。生成器允许你返回一个值,然后暂停代码的执行,稍后恢复,可以这样重复 n 次。实现这一“优雅”效果的关键字就是 yield

还是斐波那契数列:

def feb():

pre = num = 1

yield pre

yield num

while True:

pre, num = num, pre+num

if num<10:

yield num

else:return

输出如下:嗯,这次没有10以上。

>>> a = feb()

>>> for i in a:

print(i)

1

1

2

3

5

8

>>>

值得一提的是,这种协同程序是可以在 yield 值出来的时候顺便回传一个参数(或异常)的,它定义时的语法是:foo = (yield bar) 。当程序把 bar 返回出来的时候,程序挂起。这时可以通过使用 generator.send() 方法来给实例里的foo赋值。如果你不想再迭代了,还可以使用 generator.close() 方法来关闭生成器。

下面是一个从可由用户定义的整数 n 开始不断返回 n+1 的生成器:

def plus1(n=0):

n = n

while True:

var = (yield n)

if var:

n = var

else:n += 1

>>> a = plus1()

>>> for i in a:

if i>3:break

else:print(i)

0

1

2

3

>>> a.send(100)

100

>>> for i in a:

if i > 103:break

else:print(i)

101

102

103

>>> a.close()

>>> next(a)

Traceback (most recent call last):

File "", line 1, in

next(a)

StopIteration

>>>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值