一、迭代器简介

迭代:顾名思义就是重复做一些事很多次(就现在循环中做的那样)

迭代器是实现了__next__()方法的对象(这个方法在调用时不需要任何参数),它是访问可迭代序列的一种方式,通常其从序列的第一个元素开始访问,直到所有的元素都被访问才结束。 [注意]:迭代器只能前进不能后退

迭代器的优点:

使用迭代器不要求事先准备好整个迭代过程中的所有元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后元素可以不存在或者被销毁。因此迭代器适合遍历一些数量巨大甚至无限的序列。

我们已经知道,可以直接作用于for循环的数据类型有以下几种:

一类是集合数据类型,如listtupledictsetstr等;

一类是generator,包括生成器和带yield的generator function。

这些可以直接作用于for循环的对象统称为可迭代对象:Iterable

可以使用isinstance()判断一个对象是否是Iterable对象:

>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False

而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。

可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator

可以使用isinstance()判断一个对象是否是Iterator对象:

>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False

生成器都是Iterator对象,但listdictstr虽然是Iterable,却不是Iterator

二、生成迭代器

listdictstrIterable变成Iterator可以使用iter()函数:

>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True

使用内建的工厂函数iter(iterable)可以获取迭代器对象:

  语法:

    iter(collection) -> iterator

    iter(callable,sentinel) -> iterator

  说明:

    Get an iterator from an object. 

    In the first form, the argument must supply its own iterator, or be a sequence.

    In the second form, the callable is called until it returns the sentinel.

  实例展示:

使用对象内置的__iter__()方法生成迭代器
>>>L1 = [1,2,3,4,5,6]
>>>I1 = L1.__iter__()
>>>print I1
<listiterator object at 0x7fe4fd0ef550>
>>> I1.next()
1
>>> I1.next()
2
>>> I1.next()
3

你可能会问,为什么listdictstr等数据类型不是Iterator

这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

三.迭代器的应用场景

1).  如果数列的数据规模巨大

2).  数列有规律,但是依靠列表推导式描述不出来

2.数学中有个著名的斐波拉契数列(Fibonacci),数列中第⼀个数0,第⼆个数1,其后的每⼀个数都可由前两个数相加得到:

0,    1,    1,   2,    3,    5,   8,    13,    21,   34,    ...

现在我们想要通过for...in...循环来遍历迭代斐波那契数列中的前n个数。那么这个斐波那契数列我们就可以⽤迭代器来实现,每次迭代都通过数学计算来⽣成下⼀个数。

classFibIterator(object):

    """fib数列迭代器"""

    def __init__(self, n):

        """"""

        self.num1 = 0

        self.num2 = 1

        self.n = n  # 用来保存迭代的总次数

        self.i = 0  # 用来记录迭代次数
 
    def __next__(self):

        # 判断是否迭代结束,如果没有到达迭代次数,则返回数据

        if self.i < self.n:

            # 保存要返回的值

            item = self.num1

            # 计算num1, num2的值,方便下次迭代返回

            self.num1, self.num2 = self.num2,self.num1 + self.num2 

            # 记录迭代次数

            self.i += 1

            return item

        else:

            # 到达了迭代次数,抛出异常

            raise StopIteration

    def __iter__(self):

        return self 

 fib =FibIterator(20)

li = list(fib)

print(li)

四、小结

凡是可作用于for循环的对象都是Iterable类型;

凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

集合数据类型如listdictstr等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

Python的for循环本质上就是通过不断调用next()函数实现的,例如:

for x in [1, 2, 3, 4, 5]:
    pass

实际上完全等价于:

# 首先获得Iterator对象:
it = iter([1, 2, 3, 4, 5])
# 循环:
while True:
    try:
        # 获得下一个值:
        x = next(it)
    except StopIteration:
        # 遇到StopIteration就退出循环
        break

 


本文转载:CSDN博客