python中的迭代器和生成器(一)——迭代器

来源:互联网 发布:淘宝龙瞎多少钱 编辑:程序博客网 时间:2024/05/16 12:11

在学习python的资料中,经常看到迭代器和生成器,这样的名词。但到底什么是迭代器,什么是生成器?为什么会出现这样的类型,他们有什么便捷之处?

什么是迭代?

    简单的讲就是循环操作,重复某一个过程很多次。可以用for循环对可迭代对象进行迭代。

什么是可迭代对象?

    常见的迭代对象有序列,字典和文件等,另外还有其他的对象。这些可迭代对象的特点是:实现了__iter__方法。例如:

>>> alist=[1,2,3]>>> lst=alist.__iter__()>>> type(lst)<type 'listiterator'>>>> atuple=(1,2,3)>>> tup=atuple.__iter__()>>> type(tup)<type 'tupleiterator'>>>> afile=open(r"e:\test.txt",'r')>>> fl=afile.__iter__()>>> type(fl)<type 'file'>>>> astr='abc'>>> string=astr.__iter__()Traceback (most recent call last):  File "<pyshell#62>", line 1, in <module>    string=astr.__iter__()AttributeError: 'str' object has no attribute '__iter__'>>> iter(astr)<iterator object at 0x0212BE70>>>> string=iter(astr)>>> anum=1>>> iter(anum)Traceback (most recent call last):  File "<pyshell#66>", line 1, in <module>    iter(anum)TypeError: 'int' object is not iterable>>> type(string)<type 'iterator'>>>> 

我们注意到,__iter__方法返回的对象就是迭代器对象。对于字符串astr来说,没有__iter__方法,但是可以用内建函数iter()来调用,所以是可迭代对象。而对于数字anum来说,iter()无法调用,所以是不可迭代的对象。因此可以用iter()来判断一个对象是否是可迭代对象。

内建函数iter()和方法__iter__的关系:

>>> help(list.__iter__)Help on wrapper_descriptor:__iter__(...)    x.__iter__() <==> iter(x)>>> 

什么是迭代器?

迭代器就是有一个 next() 方法的对象。

在Python3.0中迭代器规则有些变化,迭代器对象应该实现__next__方法,而不是next。而新的内建函数next可以用于访问这个方法。换句话说,next(it)等同于3.0之前版本中的it.next()。

看看上面的迭代器是否都有next():

>>> lst.next()1>>> tup.next()1>>> fl.next()'\xef\xbb\xbfHello world!\n'>>> string.next()'a'

如何迭代?

在后台,for 语句在容器对象中调用iter().该函数返回一个定义了next()方法的迭代器对象,它在容器中逐一访问元素。没有后续元素时,next()就会抛出一个 StopIteration 异常, 这并不表示错误发生, 只是通知外部调用者,for语句循环结束, 迭代完成。

以下是其工作原理的示例:

>>> s='abc'>>> it=iter(s)>>> it<iterator object at 0x0228F9D0>>>> it.next()'a'>>> it.next()'b'>>> it.next()'c'>>> it.next()Traceback (most recent call last):  File "<pyshell#33>", line 1, in <module>    it.next()StopIteration>>> 

如何自定义迭代器?

    了解了迭代器协议的后台机制,就可以很容易的给自己的类添加迭代器行为。定义一个  __iter__() 方法,使其返回一个带有  next() 方法的对象。如果这个类已经定义了  next(),那么 __iter__() 只需要返回self():

>>> class Reversestr:'Iterator for looping over a swquence backwards'def __init__(self,data):self.data = dataself.index = len(data)def __iter__(self):return selfdef next(self):if self.index == 0:raise StopIterationself.index = self.index - 1return self.data[self.index]>>> for char in Reversestr('spam'):print charmaps>>> 

迭代器的优点是什么?列表不可以吗?

    如果有一个可迭代计算值的函数,那么在使用时可能只需要获得指定的值,而不需要获得所有值的列表。这时候,如果数值很多,使用列表会占用太多的内存。当然,使用迭代器更简单更优雅。

看一个不使用列表的例子,因为那样列表的长度必须无限。

>>> class Fibs():def __init__(self):self.a=0self.b=1def next(self):self.a,self.b = self.b,self.a + self.breturn self.adef __iter__(self):return self>>> 

构造一个Fibs对象:

>>> fibs = Fibs()
在for循环中使用该对象——比如查找在斐波那契数列中比500大的最小的数:

>>> for f in fibs:if f > 500:print fbreak610
因为设置了break,所以循环停止了,否则会一直继续下去。

迭代器和可迭代对象之间的关系

内建函数iter可以从可迭代对象中获取迭代器,以list为例:

>>> a=[1,2,3]>>> type(a)<type 'list'>>>> it=iter(a)>>> type(it)<type 'listiterator'>>>> it.next()1>>> it.next()2>>> it.next()3>>> it.next()Traceback (most recent call last):  File "<pyshell#140>", line 1, in <module>    it.next()StopIteration>>> 

注:iter(a)和a.__iter__()等价。

反过来,使用list构造方法可以将迭代器转化为列表:

>>> a=[1,2,3]>>> it=iter(a)>>> list(it)[1, 2, 3]>>> 

总结

可迭代对象:一个实现了__iter__方法的对象

迭代器:一个实现了next方法的对象。

关系:__iter__方法返回一个迭代器。


参考资料:

  1. Python参考手册
  2. Python基础教程(第2版)

0 0