首先向大家介绍一下iter()函数,iter()可以输入两个实参,但为了简单起见,这里忽略第二个可选参数,只介绍一个参数的形式。iter()返回一个迭代器对象。接受的参数是一个实现了__iter__()方法的容器或迭代器。对于容器而言,__iter__()方法返回一个迭代器对象,而对迭代器而言,它的__iter__()方法返回其自身,所以如果我们用一个迭代器对象it,当以它为参数调用iter(it)时,返回的是自身。
it = iter(alist)
it2 = iter(it)
assert id(it) == id(it2)
接下来讲一下迭代器协议。协议,是一种松散的约定,并没有相应的接口定义,所以简单归纳如下:
1)实现__iter__()方法,返回一个迭代器。
2)实现next()方法,返回当前的元素,并指向下一个元素的位置。如果当前位置已无元素,则跑出StopIteration异常。
>>> alist = range(2)
>>> it = alist.__iter__()
>>> it.next()
0
>>>it.next()
1
>>>it.next()
Trackback (most recent call last):
File "<stdin>",line 1,in <module>
StopIteration
与上例使用iter()内置函数不同,这次代码是 it = alist.__iter__(),可见list这一容器的确是实现了迭代器协议中容器的部分,后续的连续三次next()也映证了协议的第二条。
熟悉了迭代器协议,那么我们就使用它来遍历所有的容器。
alist = range(2)
it = iter(alist)
while True:
try:
print it.next()
except StopIteration:
break
输出:0
1
迭代器的最大好处是定义了统一的访问容器(或集合)的统一接口,所以我们可以随时定义自己的迭代器,只要实现了迭代器协议就可以了。并且,迭代器还有惰性求值的特性,它仅可以在迭代至当前元素时才计算该元素的值,之前可以不存在,在此之后可以销毁。所以非常适合遍历无穷个元素的集合,例如菲波那切数列。
class Fib(object):
def __init__(self):
self.a = 0
self.b =1
def __iter__(self):
return self
def next(self):
self.a,self.b = self._b,self._a+self._b
return self._a
for i, f in enumerate(Fib()):
print(f)
if i > 10:
break
这段代码能够打印菲波那切数列的前10项。
itertools的目标是提供一系列计算快速,内存高效的函数。它最为人所熟知的版本,算是zip,map,filter,slice的替代,izip(izip_longest),imap(startmap),ifilter(ifilterfalse),islice,它们与原来的内置函数有一样的功能,只是返回的是迭代器。
除了对于标准函数的替代,itertools还提供了一下几个有用的函数:
chain()用以同时连续地迭代多个序列,
compress(),dropwhile(),takewhile()能用以遴选序列元素
test()对序列进行n次迭代。