迭代器就是重复地做一些事情,可以简单的理解为循环,在python中实现了__iter__方法的对象是可迭代的,实现了next()(在python3中使用__next__()代替了next方法)方法的对象是迭代器,这样说起来有点拗口,实际上要想让一个迭代器工作,至少要实现__iter__方法和next方法。很多时候使用迭代器完成的工作使用列表也可以完成,但是如果有很多值列表就会占用太多的内存,而且使用迭代器也让我们的程序更加通用、优雅、pythonic。
如果一个类想被用于for ... in循环,类似list或tuple那样,就必须实现一个__iter__()方法,该方法返回一个迭代对象,然后,Python的for循环就会不断调用该迭代对象的next()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环。
不过迭代器是有限制的,例如
- 不能向后移动
- 不能回到开始
- 也无法复制一个迭代器。
 因此要再次进行迭代只能重新生成一个新的迭代器对象。
获取迭代器
- 对于python内置的可迭代(iterable)对象,可以通过内置的iter()函数来获取相应的迭代器对象。
In [1]: a = [1,2,3,45]
 
In [2]: type(a)
Out[2]: list
 
In [3]: a = iter(a)
 
In [4]: type(a)
Out[4]: list_iterator这样就获取了list相应的迭代器对象。
我们来看一下该迭代器对象的属性:
In [5]: dir(a)
Out[5]:
['__class__',
......
 '__iter__',
 '__le__',
......
 '__next__',
 '__reduce__',
......
 '__str__',
 '__subclasshook__']
 
In [6]:可见此迭代对象具有两个特殊的成员方法__iter__()和__next__(),这两个方法便是支持迭代器协议所需要实现的方法。其中__iter__()方法返回迭代器对象本身,__next__()方法返回容器的下一个元素,直到结尾抛出StopIteration异常。
我们来测试一下这个list_iterator对象的这两个方法:
__iter__()返回的对象就是迭代器对象本身。
In [1]: a = [1,2,3,45]
 
In [2]: a = iter(a)
 
In [3]: a.__iter__()
Out[3]: <list_iterator at 0x3a33f10>
 
In [4]: a
Out[4]: <list_iterator at 0x3a33f10>
 
In [5]: a is a.__iter__()
Out[5]: True
 
In [6]:__next__()方法返回容器中的值直到结尾。
In [6]: a.__next__()
Out[6]: 1
 
In [7]: a.__next__()
Out[7]: 2
 
In [8]: a.__next__()
Out[8]: 3
 
In [9]: a.__next__()
Out[9]: 45
 
In [10]: a.__next__()
------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-10-73aa2c76d676> in <module>()
----> 1 a.__next__()
 
StopIteration:
 
In [11]:- 创建迭代器对象
除了使用iter()函数将内置的序列对象转换成相应的迭代器,我们可以自己实现迭代器协议创建迭代器对象,要实现迭代器协议也就是要在类中实现__iter__()和__next__()方法。
下面写一个与list_iterator相同行为的迭代器:
# encoding:utf-8
class Fib(object):
    def __init__(self, n):
        self.gen = n
        self.a, self.b = 0, 1  # 初始化两个计数器a,b
    def __iter__(self):
        return self  # 实例本身就是迭代对象,故返回自己
    def __next__(self):
        self.a, self.b = self.b, self.a + self.b  # 计算下一个值
        if self.a > self.gen:  # 退出循环的条件
            raise StopIteration()
        return self.a  # 返回下一个值
if __name__ == '__main__':
    for i in Fib(3):
        print(i)运行结果:
1
1
2
3
[Finished in 0.1s]iter和next
- 内置函数iter()仅仅是调用了对象的__iter()__方法,所以list对象内部一定存在方法__iter__()
- 内置函数next()仅仅是调用了对象的__next()__方法,所以list对象内部不存在方法__next__(),但是Itrator中一定存在这个方法。
>>> L = [4, 5, 6]
>>> '__iter__' in dir(L)
True
>>> '__next__' in dir(L)
False
>>> I = L.__iter__()
>>> '__next__' in dir(I)
True
>>> from collections import Iterable, Iterator
>>> isinstance(L, Iterable)
True
>>> isinstance(L, Iterator)
False
>>> isinstance(I, Iterable)
True
>>> isinstance(I, Iterator)
TrueIterator继承自Iterable,从下面的测试中可以很方便的看到Iterator包含__iter()__和__next()__方法,而Iteratble仅仅包含__iter__()。
>>> from collections import Iterator, Iterable
>>> help(Iterator)
Help on class Iterator:
 
class Iterator(Iterable)
 |  Method resolution order:
 |      Iterator
 |      Iterable
 |      builtins.object   
 |**注解:从这里可以看出Iterable继承自object, Iterator继承自Iterable。
 |  Methods defined here:
 |
 |  __iter__(self)
 |
 |  __next__(self)
 |      Return the next item from the iterator. When exhausted, raise StopIteration
......
>>> help(Iterable)
Help on class Iterable:
 
class Iterable(builtins.object)
 |  Methods defined here:
 |
 |  __iter__(self)
......可迭代对象和迭代器对象
可迭代对象是实现了__iter__()方法的对象,__iter__()可以返回一个迭代器对象。
迭代器对象是实现了__next__()方法的对象,其中他的__iter__()返回的是迭代器对象本身。
class ListIterable(object):
    def __init__(self, data):
        self.__data = data
 
    def __iter__(self):
        print("call iterable __iter__().")
        return ListIterator(self.__data)
 
 
class ListIterator(object):
    def __init__(self, data):
        self.__data = data
        self.__count = 0
 
    def __iter__(self):
        print("call iterator __iter__().")
        return self
 
    def __next__(self):
        print("call iterator __next__().")
        if self.__count < len(self.__data):
            val = self.__data[self.__count]
            self.__count += 1
            return val
        else:
            raise StopIteration上述例子中有着一个可迭代类和迭代器类
print('initialize a Iterable object......')
a = ListIterable([1, 2, 4, 5, 6])
print(type(a))
print('get Iterator object from __iter__ ')
b = a.__iter__()
print(type(b))运行结果
initialize a Iterable object......
<class '__main__.ListIterable'>
get Iterator object from __iter__ 
call iterable __iter__().
<class '__main__.ListIterator'>
[Finished in 0.1s]可见a是iterable对象(实现了__iter__()),b是iterator对象(实现了__next__())。
下面看看这样做是不是就可以重复多次迭代了:
a = ListIterable([1, 2, 4, 5, 6])
print([i for i in a])
print([i for i in a])运行结果:
call iterable __iter__().
call iterator __next__().
call iterator __next__().
call iterator __next__().
call iterator __next__().
call iterator __next__().
call iterator __next__().
[1, 2, 4, 5, 6]
call iterable __iter__().
call iterator __next__().
call iterator __next__().
call iterator __next__().
call iterator __next__().
call iterator __next__().
call iterator __next__().
[1, 2, 4, 5, 6]
[Finished in 0.1s]重复迭代是可以了,从输出中我们可以看出一些什么来
- 我们在使用迭代工具对iterable对象进行迭代的时候首先调用的是iterable的__iter__()方法,返回一个迭代器对象,也就是ListIterator的实例。
- 然后再遍历的时候是调用iterator的next方法输出值。
 这样就可以解释了为什么这样处理能够多次迭代了,因为每次使用迭代工具迭代的时候都会调用__iter__()返回一个新的迭代器对象,这样就相当于创建多个迭代器了,自然可以看起来是重复迭代了!
可变对象和迭代器
在迭代可变对象时候,一个序列的迭代器只是记录当前到达了序列中的第几个元素,所以如果在迭代过程中改变了序列的元素。更新会立即反应到所迭代的条目上。
In [13]: c = [1,2,3,4,5]
 
In [14]: d = iter(c)
 
In [15]: for i in c:
   ....:     print(i)
   ....:     c.remove(i)
   ....:
1
3
5这就是边迭代边更改元素带来的危险了!
复制迭代器
迭代器是一次性消耗品,使用完了以后就空了,请看。
>>> L=[1,2,3]
>>> I=iter(L)
>>> for i in I:
...     print(i, end='-')
...
1-2-3-
>>>next(I)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> I=iter(L)
>>> J=I
>>> next(I)
1
>>> next(J)
2
>>> next(I)
3
>>> next(J)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration说明迭代器的复制只是浅复制而已。
 
        