• Python基础-16生成器-迭代器


    16.生成器-迭代器

        可循环迭代的对象称为可迭代对象,迭代器和生成器函数是可迭代对象,在Python中提供了定义迭代器和生成器的协议和方法。

    16.1 迭代和可迭代对象

    16.1.1 可迭代对象、迭代器和可迭代协议

    1.可迭代对象

        在Python中,实现了__iter__()的对象是可迭代对象(Iterable)。使用内置函数iter(obj),可以调用可迭代对象obj的__iter__()方法,并返回一个迭代器(iterator)。如字符串、元组、列表等都是可迭代对象,生成器函数和生成器表达式也是可迭代对象。判断一个对象是否为可迭代对象,可使用以下方式:

    >>> from collections import abc
    >>> isinstance((1,2,3,4),(abc.Iterable,))
    True
    >>> isinstance("abcdef",(abc.Iterable,))
    True
    >>> isinstance(123,(abc.Iterable,))
    False
    >>> isinstance("123",(abc.Iterable,))
    True
    >>> isinstance({1,2,3},(abc.Iterable,))
    True
    >>> isinstance({"a":1,"b":2},(abc.Iterable,))
    True
    

    2.迭代器

        实现了__next__的对象是迭代器,可以使用内置函数next(),调用迭代器的__next__()方法,依次返回下一个值,如果没有值,则抛出异常StopIteration。使用迭代器可以实现对象的迭代循环,让程序更加通用,高效。示例如下所示:

    >>> from collections import abc
    >>> tempA=(i**2 for i in range(10))
    >>> isinstance(tempA,(abc.Iterable,))
    True
    >>> tempB={i*2 for i in range(10)}
    >>> isinstance(tempB,(abc.Iterable,))
    True
    

    3.迭代器协议

        迭代器对象必须实现两个方法__iter__()__next__(),这两个方法被称为迭代器协议。__iter__()用于返回对象本身,以方便使用循环语句(for)进行迭代,__next__()用于返回下一元素。示例如下所示:

    >>> from collections import abc
    >>> tempA=(i**2 for i in range(10))
    >>> help(tempA)
     |  __iter__(self, /)
     |      Implement iter(self).
     |  
     |  __next__(self, /)
     |      Implement next(self).
    

    16.1.2 可迭代对象的迭代:iter和next函数

        使用内置函数iter(iterable),可以返回可迭代对象iterable的迭代器;使用内置函数next()函数,可依次返回迭代器对象的下一个值,如果没有值,则抛出异常StopIteration。示例如下所示:

    >>> temp=[1,2,3,4] # 可迭代对象
    >>> v=iter(temp)   # 通过内置函数iter获取iterator
    >>> next(v)        # 通过内置函数next获取值
    1
    >>> next(v)
    2
    >>> next(v)
    3
    >>> next(v)
    4
    >>> next(v)       # 当没有值,则抛出异常StopIteration
    Traceback (most recent call last):
      File "<input>", line 1, in <module>
    StopIteration
    

        除了使用next函数个,也可以使用while循环可迭代对象,如下所示:

    temp=[1,2,3,4]
    v=iter(temp)
    while True:
        try:
            value=next(v)
        except StopIteration:
            break
        print(value,end=" ")
    

    运行结果如下所示:

    1 2 3 4
    

    16.1.3 可迭代对象的迭代:for语句

        实际项目中,通常会使用for语句实现可迭代对象的迭代。Python中的for循环实现了自动迭代可迭代对象的功能,如下所示:

    >>> temp=[1,2,3,4]
    >>> for item in temp:
    ...     print(item,end=" ")
    ...     
    1 2 3 4 
    >>> for item in "abcdef":
    ...     print(item,end="-")
    ...     
    a-b-c-d-e-f-
    

    16.2 自定义可迭代对象和迭代器

        创建一个类,定义__iter__()和__next__()两个方法。实例化该类的对象,即为可迭代对象,也是迭代器。示例如下所示:

    class Fibonacci:
    
        def __init__(self):
            self._first=0
            self._second=1
    
        def __next__(self):
            # f(n)=f(n-1)+f(n-2)
            self._first,self._second=self._second,self._first+self._second
            return self._first
        def __iter__(self):
            return self
    
    fib=Fibonacci()
    for f in fib:
        if f<100:
            print(f,end=" ")
        else:
            break
    

    输出结果如下所示:

    1 1 2 3 5 8 13 21 34 55 89
    

    16.3 生成器函数

        在函数定义中,如果使用关键字yield语句代替return返回一个值,则表示定义了一个生成器函数(generator)。生成器函数使用yield语句返回一个值,然后保存当前函数的整个执行状态,等待下一次调用。生成器函数是一个迭代器,是可迭代对象。示例如下所示:

    >>> def generatorSample(n):
    ...     for i in range(n):
    ...         yield i**2
    ...         
    >>> f=generatorSample(5)
    >>> f
    <generator object generatorSample at 0x00000260CE70E7C8>
    >>> item=iter(f)    # 通过内置函数iter获得iterator
    >>> next(item)      # 通过内置函数next获取一个值
    0
    >>> next(item)      # 通过内置函数next获取一个值
    1
    >>> for i in f:
    ...     print(i,end=" ")
    ...     
    4 9 16              # 使用for循环获取剩下的值
    

        下面我们再用生成器生成Fibonacci数列,示例代码如下所示:

    def Fibonacci():
        first,second=0,1
        while True:
            first,second=second,first+second
            yield first
    
    for f in Fibonacci():
        if f<100:
            print(f,end=" ")
        else:
            break
    

    输出结果如下所示:

    1 1 2 3 5 8 13 21 34 55 89 
    

    16.4 反向迭代器:reversed迭代器

        使用内置函数reversed(),可以实现一个反向迭代器。如果一个可迭代对象实现了__reversed__()方法,则可使用reversed()函数获得其反向可迭代对象。示例如下所示:

    >>> reversed([1,2,3,4,5])
    <list_reverseiterator object at 0x00000260CF0D8908>
    >>> for item in reversed([1,2,3,4,5]):
    ...     print(item,end=" ")
    ...     
    5 4 3 2 1
    

        实现一个可反向迭代的迭代器示例:

    class CountSample:
    
        def __init__(self,startIndex):
            self._startIndex=startIndex
    
        # 正向迭代
        def __iter__(self):
            n=self._startIndex
            while n > 0:
                yield n
                n-=1
    
        # 反向迭代
        def __reversed__(self):
            n=1
            while n<= self._startIndex:
                yield n
                n+=1
    
    if __name__ == '__main__':
        obj=CountSample(10)
        print("正向迭代")
        for item in obj :
            print(item,end=" ")
        print("
    反向迭代")
        for item in reversed(obj):
            print(item,end=" ")
    

    输出结果如下所示:

    正向迭代
    10 9 8 7 6 5 4 3 2 1
    反向迭代
    1 2 3 4 5 6 7 8 9 10
    

    16.5 生成器表达式

        使用生成器表达式,可以简便快捷返回一个生成器。生成器表达式的语法和前面所讲的列表解析式基本一样,区别在于生成器表达式使用()代表[],基本使用格式如下所示:

    ( expr for iterVar in iterable )
    ( expr for iterVar in iterable if condition)
    

        表达式expr使用每次迭代内容iterVar,计算生成一个列表。如果在指定条件表达式condition,则只有满足条件的iterable元素参与迭代。如下所示:

    >>> (i**2 for i in range(10))
    <generator object <genexpr> at 0x00000260CF0B0EC8> # 输出表明是一个生成器
    >>> for item in (i**2 for i in range(10)):
    ...     print(item,end=" ")
    ...     
    0 1 4 9 16 25 36 49 64 81
    
    >>> for item in (i**2 for i in range(10) if i%2==0):
    ...     print(item,end=" ")
    0 4 16 36 64 
    

    16.5 小结

    • 1.可迭代对象(iterable):可循环迭代的对象称为可迭代对象
    • 2.迭代器(iterator): 实现了__iter__()__next__()的对象,__iter__返回迭代器自身,__next__返回迭代器中的下一个值,如果没有元素,则抛出StopIteration异常
    • 3.生成器(generator):一种特殊的迭代器,使用关键字yield定义,生成器一定是迭代器,反之则不成立。
    • 4.迭代对象与迭代器的示意图如下所示:

    160501迭代对象与迭代器.png

    本文地址:https://www.cnblogs.com/surpassme/p/13028211.html
    本文同步在微信订阅号上发布,如各位小伙伴们喜欢我的文章,也可以关注我的微信订阅号:woaitest,或扫描下面的二维码添加关注:
    MyQRCode.jpg

  • 相关阅读:
    JAVA开发环境配置
    Java volatile关键字解惑
    Java实验案例(接口)
    Java 实验案例(多态)
    Eclipse 快捷键大全
    全球免费开放的电子图书馆
    Java 实验案例(类和对象篇)
    Java IO流(二)
    Linux zsh 实用配置
    Js远程调用封装
  • 原文地址:https://www.cnblogs.com/surpassme/p/13028211.html
Copyright © 2020-2023  润新知