Python 高级编程之初识迭代器

1. 可迭代对象

在高级语言中,迭代这一概念非常普遍。所谓迭代,就是依次遍历一个序列中的每个元素。而可迭代对象,就像一个容器,让你能够遍历它的所有元素。

常见的可迭代对象有列表、元组、字典、集合等。可迭代对象既可以是实际的序列,如列表,也可以是在迭代过程中一次产生一个元素的虚拟序列。

像列表这样的实际序列,是将全部的元素都保存在内存中,当元素个数较多时,内存占用比较大。而虚拟序列不同,它在迭代过程中即时给出当前元素的值,因此相比于实际的序列,虚拟序列占用的内存很小。

2. 迭代协议

Python中的迭代协议(Iteration Protocal),就是可迭代对象必须遵循的协议。当一个可迭代对象的 next 方法被调用时,会给出它的下一个元素,如果到达结果末尾,则触发 StopIteration 异常。

在Python中,可迭代对象必须具有 __iter__ 方法,该方法通常返回对象本身,也可以返回其它可迭代对象。我们可以通过观察某个对象是否具有 __iter__ 方法来判断它是否可以迭代。

注意:在 Python2.x 版本中,可迭代对象对应的方法是 next ,在 Python3.x 版本中,可迭代对象的方法是 __next__

3. 迭代器

可迭代对象可以通过Python内置函数 iter 来生成一个迭代器(iterator)。

例如,我们可以对列表使用该函数从而得到一个迭代器

>>> L = [1, 2, 3]
>>> I = iter(L)
>>> I.next()
1
>>> I.next()
2
>>> I.next()
3
>>> I.next()
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
StopIteration

正如前面的迭代协议里提到的,当迭代器达到末尾时,便会触发 StopIteration 异常。

这是手动调用对象的 next 方法进行迭代的例子。但通常情况下,我们更多的是使用 for 循环语句来自动迭代。

>>> L = [1, 2, 3]
>>> for i in L:
...    print i
>>> 1
>>> 2
>>> 3

for 循环语句在迭代时,自动调用了内置的 iter 来生成迭代器,省去了我们手动使用 iter(L) 生成迭代器这一步。

严格意义上讲,在Python中通过 iter 函数生成的对象叫做迭代器,而本身支持迭代的对象叫做可迭代对象。但在不引起误解的情况下,有时也把可迭代对象叫做迭代器。

4. 实现自己的迭代器

我们可以用类实现一个迭代器,在类中添加 next 方法和 __iter__ 方法。

例如,我们实现一个类似于 xrange 的产生整数序列的迭代器:

class yrange:
    def __init__(self, start=0, stop=0):
        self.start = start
        self.stop = stop
    def __iter__(self):
        return self
    def next(self):
        if(self.start < self.stop):
            start = self.start
            self.start += 1
            return start
        else:
            raise StopIteration

运行结果如下

>>> for y in yrange(5, 8):
...     print y
5
6
7

Python内置的一些函数如 listsumsorted 都支持迭代器作为参数,例如:

>>> list(yrange(1,4))
[1, 2, 3]
>>> sum(yrange(1, 4))
6
>>> sorted(yrange(1, 4), reverse=True)
[3, 2, 1]

5. 内置类型迭代器

在很多情况下,使用迭代器能够简化代码,还能够提高程序的性能,Python中有几种内置类型都具有其适用的迭代器。

5.1. 文件迭代器

读取文件时,我们经常使用文件对象的 readlines 方法。该方法实际上是返回一个列表,列表中存储了文件的每一行。

f = open('post.txt')
for line in f.readlines():
    print line

使用这种方法来读取文件时,存在一个问题,就是内存占用较大。因为我们将文件内容一次性读取到了列表中,然后再迭代这个列表,这样效率会低一些。

实际上,当我们打开文件后,open 函数就返回了一个文件迭代器。文件迭代器是以C语言的速度执行的,因此速度更快,而且空间占用很小。

上面的代码改用文件迭代器的形式之后如下:

for line in open('post.txt'):
    print line

非常简洁而且高效!

5.2. 字典迭代器

Python的字典有一个迭代器,在迭代时会一次返回一个键。

>>> D = {'a':1, 'b':2, 'c':3}
>>> for key in D:
...     print key, D[key]
a 1
b 2
c 3

你也可以使用字典的 items 方法所返回的列表,只不过当字典比较大时,这种方法会占用较大空间。

>>> D = {'a':1, 'b':2, 'c':3}
>>> for key, value in D.items():
...     print key, value
a 1
b 2
c 3

除此之外,元组、集合等类型都有自己的迭代器,这些类型的对象可以直接在迭代时使用。

参考文章:5. Iterators & Generators — Python Practice Book

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注