1.8 使用迭代器
毫无疑问,对于数据科学的程序而言,数据是极其重要的输入。数据的大小是可变的,有些能装载到内存中,有些则不能。而记录访问架构也是随一种数据格式到另一种而变化。有趣的是,不同的算法处理数据时,需要的是可变长度的组块。例如,假如你在写一个随机梯度下降的算法,你希望在每个时间片传送5000条记录的数据块,如果你对如何访问数据、理解数据格式、依次传送数据、给调用者需要的数据等流程有着清晰的概念,那你才能成功。这样能让你写出清晰的代码。大多数时候,最有趣的部分是我们如何处理数据,而不是我们怎么访问这些数据。Python给我们提供了迭代器这种优雅的方式来处理所有这些需求。
1.8.1 准备工作
Python中的迭代器实现了一种迭代器模式,它让我们可以一个接一个地处理一个序列,但不需要真正实现整个序列。
1.8.2 操作方法
我们来创建一个简单的迭代器,叫作“简单计数器”,用一些代码演示了怎样高效地使用迭代器。
# 1.写一个简单的迭代器
class SimpleCounter(object):
def __init__(self, start, end):
self.current = start
self.end = end
def __iter__(self):
'Returns itself as an iterator object'
return self
def next(self) :
'Returns the next value till current is lower than end'
if self.current > self.end:
raise StopIteration
else:
self.current += 1
return self.current - 1
# 2.现在来访问这个迭代器
c = SimpleCounter(1,3)
print c.next()
print c.next()
print c.next()
print c.next()
# 3.另外一种访问方式
for entry in iter(c):
print entry
1.8.3 工作原理
在第1步中,我们定义了一个名为Simple Counter的类,构造函数_init_有两个参数:起始和结束,来定义序列的开始和结束。请注意_iter_和next这两个方法,在Python中想要成为一个迭代器的对象必须都支持这两个函数。_iter_返回整个类对象作为一个迭代器对象,next方法返回迭代器里的下一个值。
如第2步所示,我们可以使用next()函数访问迭代器中的连续元素。Python也提供了一个方便的函数iter(),它能用来在循环体中循序访问元素,如第3步所示。它在内部实现中使用了next函数。
请注意,一个迭代器对象只能被使用一次。运行上面的代码之后,如果我们仍要像下面这样访问迭代器。
print next(c)
系统会抛出一个StopIteration异常。在序列已经到尾部的时候再调用c.next() 会触发一个StopIteration异常。
raise StopIteration
StopIteration
>>>
iter()函数会处理这个异常,当数据访问完成的时候退出循环。
1.8.4 更多内容
再看另一个迭代器的示例,我们需要在程序中访问一个非常大的文件,不过,在代码里,我们每次只访问一行,直到读完整个文件。
f = open(some_file_of_interest)
for l in iter(f):
print l
f.close()
在Python里,一个文件对象就是一个迭代器,它支持iter()和next()函数。因此,我们每次只处理一行数据,而不是将全部文件加载到内存中。
迭代器给了你自由,你可以让你的应用程序自己定义访问你的数据源的方式。
下面的链接提供了Python中多种多样的迭代器使用方法的信息,如无限迭代器itertools中的count()、cycle()以及repeat()等。
https://docs.python.org/2/library/itertools.html#itertools.cycle。