美文网首页程序员大数据 爬虫Python AI Sql
Python难点解析---初级篇3.迭代(可迭代、迭代器、生成器

Python难点解析---初级篇3.迭代(可迭代、迭代器、生成器

作者: ZeroTryTryTry | 来源:发表于2017-02-23 23:41 被阅读653次

    什么是迭代

    Wiki定义:是重复反馈过程的活动,其目的是为了接近并到达所需的目标或结果。

    在程序中,迭代是一种遍历集合元素的方式,我们可以通过索引值递增来遍历集合元素,而迭代是遍历集合元素另一种方式。

    下面是使用索引来进行遍历集合元素的方式:

    val = [1,2,3,4,5]
    for i in range(len(val)):
        retVal = val[i]
    

    这种方式在C++中很常见,在Python中我们可以用更简洁的语法来进行遍历,也就是迭代

    三个关键字

    说到迭代,在Python里就会提到下面三个关键词:

    • Iterable(可迭代)
    • iterator(迭代器)
    • generator(生成器)

    这三个关键字,可能从一开始的某段代码你就接触到了,只是你没有发觉,代码是这样的。

    val = [1,2,3,4,5]
    for i in val:
        print i
    

    上面这个for...in,就是Python中迭代器的语法糖。好了,现在你可能开始在想这个for做了什么事了,先把这个疑问放在心里,我们先一步步来解析上面的几个关键字。

    Iterable 可迭代

    先来看个反面教材,如果我们用for...in语法糖去遍历一个int会怎样???

    intVal = 1024
    for _ in intVal:
        pass
    
    >>>TypeError: 'int' object is not iterable
    

    从上面的错误可以看到,整数类型的对象不是可迭代的,也就是说for..in只适用于iterable对象,那么什么类型的对象才是iterable(可迭代)呢。

    在Python中,实现了_iter_函数的类型都是可迭代的,例如list,tuple,dict等

    可以用dir函数查看一下是否存在协议函数__iter__

    print '__iter__' in dir(dict)
    print '__iter__' in dir(list)
    print '__iter__' in dir(tuple)
    
    >>>True                                                                                                                                                                                                                                   
    >>>True                                                                                                                                                                                                                                   
    >>>True 
    

    通过上面的方式我们可以判断一个对象是不是可迭代的,当然我们还有另外一种更接地气的方法。

    l = [1]
    from collections import Iterable
    print isinstance(l, Iterable)  #注意这里只能用实例进行判断,而不能用list判断
    

    iterator 迭代器

    对于一个可迭代的对象,我们需要借助迭代器来对其进行迭代,那么我们怎么才能得到一个迭代器呢?

    iter()方法

    通过使用iter方法,我们可以得到一个迭代器,记住,要传入一个可迭代对象做为参数:

    l = [1]
    o = iter(l)
    print type(o)
    >>><type 'listiterator'>
    

    从上面的代码可以看到,我们通过将一个可迭代对象传给iter方法得到了一个迭代器,那么有了这个迭代器之后,我们应该怎么迭代呢?

    next()方法

    调用迭代器next方法可以对元素进行遍历,但是next方法是不能无限使用的:

    l = [1, 2, 3]
    o = iter(l)
    print o.next()
    print o.next()
    print o.next()
    print o.next()
    
    >>>1                                                                                                                                                                                                                                      
    >>>2                                                                                                                                                                                                                                      
    >>>3                                                                                                                                                                                                                                      
    >>>Traceback (most recent call last):                                                                                                                                                                                                     
      File "e:\Microsoft VS Code\TestFiles\test.py", line 63, in <module>                                                                                                                                                                  
        print o.next()                                                                                                                                                                                                                     
    StopIteration  
    

    通过next方法我们可以一个个的遍历可迭代对象中的元素,当遍历结束的时候,会引发异常StopIteration


    迭代器类

    除了以上的方法,我们还可以构造一个类来进行迭代,这个类需要实现next__iter__方法,下面构造了一个斐波那契数列:

    class FabIteratorClass(object):
        def __init__(self, max):
            self.m_Max = max
            self.m_Idx = 0
            self.m_a = 0
            self.m_b = 1
    
        def __iter__(self):
            return self
    
        def next(self):
            if self.m_Idx < self.m_Max:
                ret = self.m_b
                self.m_a, self.m_b = self.m_b, self.m_a + self.m_b
                self.m_Idx += 1
                return ret
            raise StopIteration()
    
    for val in FabIteratorClass(3):
        print val
    
    >>>1
    >>>1
    >>>2
    

    所以,作为一个迭代器,他的特征如下:

    • 拥有__iter__方法,或者由iter方法返回
    • 拥有next方法
    • 会产生StopIteration异常

    生成器

    说到生成器,那么一定会说到一个关键字yield,只要一个函数里出现了这个关键字,我们就把这个函数称为生成器,生成器是一种内存友好的函数,例如平时用到的xrange函数,就是一个生成器,生成器不会把所有值预先生成,而是在需要时才生成,是一种Lazy Evaluation的做法。生成器也是迭代器的一种!

    同样是斐波那契数列,我们用生成器处理一下:

    def fab(max):
        idx = 0
        a = 0
        b = 1
        while idx < max:
            ret = b
            a, b = b, a + b
            idx += 1
            yield ret
    
    c = fab(5)
    print type(c)
    for val in c:
        print val
    >>><type 'generator'> 
    >>>1                                                                                                                                                                                                                                      
    >>>1                                                                                                                                                                                                                                      
    >>>2                                                                                                                                                                                                                                      
    >>>3                                                                                                                                                                                                                                      
    >>>5 
    

    总结:

    • 三者的继承关系是这样:generator--->Iterator--->Iterable
    • 迭代器类型需要实现__iter__next方法,生成器是一种特殊的迭代器,内部支持了生成器协议,不需要明确定义iter()和next()方法
    • 迭代器一定是可迭代对象,但是可迭代对象不一定是迭代器

    相关文章

      网友评论

        本文标题:Python难点解析---初级篇3.迭代(可迭代、迭代器、生成器

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