美文网首页
python迭代器

python迭代器

作者: youngkun | 来源:发表于2017-09-05 22:01 被阅读0次

    迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。

    可迭代对象
    以直接作用于 for 循环的数据类型有以下几种:
    一类是集合数据类型,如 list 、 tuple 、 dict 、 set 、 str 等;
    一类是 generator ,包括生成器和带 yield 的generator function。
    这些可以直接作用于 for 循环的对象统称为可迭代对象: Iterable 。

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


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

    迭代器
    迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,知道所有的元素被访问完结束。迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退。

    使用迭代器的优点
    对于原生支持随机访问的数据结构(如tuple、list),迭代器和经典for循环的索引访问相比并无优势,反而丢失了索引值(可以使用内建函数enumerate()找回这个索引值)。但对于无法随机访问的数据结构(比如set)而言,迭代器是唯一的访问元素的方式。

    另外,迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件,或是斐波那契数列等等。

    迭代器更大的功劳是提供了一个统一的访问集合的接口,只要定义了iter()方法对象,就可以使用迭代器访问。

    迭代器有两个基本的方法

    next方法:返回迭代器的下一个元素
    iter方法:返回迭代器对象本身
    下面用生成斐波那契数列为例子,说明为何用迭代器

    def fab(max): 
        n, a, b = 0, 0, 1 
        while n < max: 
            print b 
            a, b = b, a + b 
            n = n + 1
    

    直接在函数fab(max)中用print打印会导致函数的可复用性变差,因为fab返回None。其他函数无法获得fab函数返回的数列。

    def fab(max): 
        L = []
        n, a, b = 0, 0, 1 
        while n < max: 
            L.append(b) 
            a, b = b, a + b 
            n = n + 1
        return L
    

    代码满足了可复用性的需求,但是占用了内存空间,最好不要。

    对比

    for i in range(1000): pass
    for i in xrange(1000): pass
    

    前一个返回1000个元素的列表,而后一个在每次迭代中返回一个元素,因此可以使用迭代器来解决复用可占空间的问题

     class Fab(object): 
        def __init__(self, max): 
            self.max = max 
            self.n, self.a, self.b = 0, 0, 1 
    
        def __iter__(self): 
            return self 
    
        def next(self): 
            if self.n < self.max: 
                r = self.b 
                self.a, self.b = self.b, self.a + self.b 
                self.n = self.n + 1 
                return r 
            raise StopIteration()
    

    执行

    >>> for key in Fabs(5):
        print key
     
         
    1
    1
    2
    3
    5
    

    Fabs 类通过 next() 不断返回数列的下一个数,内存占用始终为常数

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

    >>> lst = range(5)
    >>> it = iter(lst)
    >>> it
    <listiterator object at 0x01A63110>
    

    使用next()方法可以访问下一个元素:

    >>> it.next()
    0
    >>> it.next()
    1
    >>> it.next()
    2
    

    python处理迭代器越界是抛出StopIteration异常

    >>> it.next()
    3
    >>> it.next
    <method-wrapper 'next' of listiterator object at 0x01A63110>
    >>> it.next()
    4
    >>> it.next()
     
    Traceback (most recent call last):
      File "<pyshell#27>", line 1, in <module>
        it.next()
    StopIteration
    

    了解了StopIteration,可以使用迭代器进行遍历了

    lst = range(5)
    it = iter(lst)
    try:
        while True:
            val = it.next()
            print val
    except StopIteration:
        pass
    

    结果

    >>>
    0
    1
    2
    3
    4
    

    事实上,因为迭代器如此普遍,python专门为for关键字做了迭代器的语法糖。在for循环中,Python将自动调用工厂函数iter()获得迭代器,自动调用next()获取元素,还完成了检查StopIteration异常的工作。如下

    >>> a = (1, 2, 3, 4)
    >>> for key in a:
        print key
    
        
    1
    2
    3
    4
    

    首先python对关键字in后的对象调用iter函数迭代器,然后调用迭代器的next方法获得元素,直到抛出StopIteration异常。

    定义迭代器
    下面一个例子——斐波那契数列

    class Fabs(object):
        def __init__(self,max):
            self.max = max
            self.n, self.a, self.b = 0, 0, 1  #特别指出:第0项是0,第1项是第一个1.整个数列从1开始
        def __iter__(self):
            return self
        def next(self):
            if self.n < self.max:
                r = self.b
                self.a, self.b = self.b, self.a + self.b
                self.n = self.n + 1
                return r
            raise StopIteration()
    
    print Fabs(5)
    for key in Fabs(5):
        print key
    

    结果

    <__main__.Fabs object at 0x01A63090>
    1
    1
    2
    3
    5
    

    iter()函数
    生成器都是 Iterator 对象,但 list 、 dict 、 str 虽然是 Iterable ,却不是 Iterator 。

    把 list 、 dict 、 str 等 Iterable 变成 Iterator 可以使用 iter() 函数:

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

    总结
    • 凡是可作用于 for 循环的对象都是 Iterable 类型;
    • 凡是可作用于 next() 函数的对象都是 Iterator 类型
    • 集合数据类型如 list 、 dict 、 str 等是 Iterable 但不是 Iterator ,不过可以通过 iter() 函数获得一个 Iterator 对象。
    • 目的是在使用集合的时候,减少占用的内容。

    相关文章

      网友评论

          本文标题:python迭代器

          本文链接:https://www.haomeiwen.com/subject/rimpjxtx.html