• 『无为则无心』Python基础 — 62、Python中自定义迭代器


    1、迭代器对象的创建

    迭代器是一种可以被遍历的对象,并且能够作用于next()函数,迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束,迭代器只能往后遍历,不能回溯。不像列表,你随时可以取后面的数据,也可以返回头取前面的数据,迭代器通常要实现两个基本方法next()iter()

    概括的说,一个对象实现了__iter__()__next__()方法,那么它就是一个迭代器对象。

    但是只实现了__iter__()方法没有实现__next__()方法,就只是一个可迭代对象。

    例如:

    python
    # 3.6之前的版本是不需要带.abc的,3.7就会提示需要加.abc
    from collections.abc import Iterable, Iterator
    
    
    class IterA:
    
        def __iter__(self):
            # 我们这里返回一个列表
            return [1, 2, 3]
    
    
    class IterB:
        pass
    
    
    iterA = IterA()
    iterB = IterB()
    
    # 可以看到iterA 是一个可迭代对象
    # iterB 是一个不可迭代对象
    print(isinstance(iterA, Iterable))  # True
    print(isinstance(iterB, Iterable))  # False
    
    # iterA是一个可迭代对象,但并不是一个迭代器对象
    # 因为IterA类中并没有实现next方法
    print(isinstance(iterA, Iterator))  # False

    我们在IterA类中实现__next__()方法,IterA类就变成了一个迭代器对象了。

    python
    # 3.6之前的版本是不需要带.abc的,3.7就会提示需要加.abc
    from collections.abc import Iterable, Iterator
    
    
    class IterA:
    
        def __iter__(self):
            # 我们这里返回一个列表
            return [1, 2, 3]
    
        def __next__(self):
            pass
    
    
    iterA = IterA()
    
    # 可以看到iterA 是一个可迭代对象
    # iterB 是一个不可迭代对象
    print(isinstance(iterA, Iterable))  # True
    
    
    # iterA对象也是要给迭代器对象
    print(isinstance(iterA, Iterator))  # True

    2、实际应用案例

    python
    """
    1.迭代器的应用场景
        1).如果数列的数据规模巨大
        2).数列有规律,但是依靠列表推导式描述不出来
     
    
    2.数学中有个著名的斐波那契数列(Fibonacci),
    数列中第⼀个数0,第⼆个数1,其后的每⼀个数都可由前两个数相加得到:
    如下:
    0,    1,    1,   2,    3,    5,   8,    13,    21,   34,    ...
    
    现在我们想要通过for...in...循环来遍历迭代斐波那契数列中的前n个数。
    那么这个斐波那契数列我们就可以⽤迭代器来实现,
    每次迭代都通过数学计算来⽣成下⼀个数。
    
    """
    from collections.abc import Iterable, Iterator
    
    class FibIterator(object):
        """
            fib数列迭代器
        """
    
        # 初始化方法
        def __init__(self, count):
            # 斐波拉契数列中的前两个数
            self.num1 = 0
            self.num2 = 1
    
            # 用来保存迭代的总次数
            self.count = count
            # 用来记录迭代次数(计数器)
            self.i = 0
    
        # 实现__iter__表示FibIterator是一个可迭代对象
        # 返回对象自己。是一个可迭代对象
        def __iter__(self):
            return self
    
        # 实现__next__方法,是FibIterator定义为迭代器对象的重要条件之一
        def __next__(self):
            # 判断是否迭代结束,如果没有到达迭代次数,则返回数据
            # self.count 需要迭代的次数
            # self.i已迭代次数
            if self.i < self.count:
    
                item = self.num1
                # 计算num1, num2的值,方便下次迭代返回
                # 这里运用的是序列的封包与解包,不会的可以看我以前的文章(元组)
                self.num1, self.num2 = self.num2, self.num1 + self.num2
    
                # 执行一次next方法,计数器+1
                self.i += 1
                # 返回新获得的数,
                # 也就是前两个数求和的第三个数
                return item
            else:
                # 到达了迭代次数,抛出异常
                raise StopIteration
    
    
    # 创建一个fib数列迭代器对象
    fibIter = FibIterator(15)
    
    # fibIter对象是一个迭代器
    print(isinstance(fibIter, Iterable))  # True
    print(isinstance(fibIter, Iterator))  # True
    
    # 转换为列表查看fib对象内容
    # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]
    print(list(fibIter))
    
    # 遍历,可执行
    for li in fibIter:
        print(li)

    3、总结:

    (1)整理总结

    • 对象是否实现了__iter__方法,如果实现了,该对象就是一个可迭代对象。
    • 一个对象实现了__iter__()__next__()方法,那么它就是一个迭代器对象。
    • 可以使用iter()函数把可迭代对象(Iterable)变成迭代器对象(Iterator)。
    • 通过isinstance()函数,可以判断一个对象是否是Iterable对象或者是Iterator对象。
      python
      print(isinstance(fibIter, Iterable))  
      print(isinstance(fibIter, Iterator)) 

    (2)迭代协议

    当任何可迭代对象传入到for循环或其他迭代工具中进行遍历时,迭代工具都是先通过iter()函数获得与可迭代对象对应的迭代器,然后再对迭代器调用next()函数,不断的依次获取元素,并在捕捉到StopIteration异常时,确定完成迭代,这就是完整的迭代过程,这也称之为“迭代协议”。

    (3)为什么任何Python序列都可迭代?

    1. 都实现了__getitem__方法
    2. 标准序列也都实现了__iter__方法
    3. 实现了__getitem__方法,而且其参数是从0开始的索引,这种对象也可迭代,但它不是一个可迭代对象。
      原因是:如果没有实现__iter__方法,但实现了__getitem__方法,__getitem__()方法可以通过iter()函数转成Iterator,即可以在for循环中使用,按顺序(从0开始)获取元素。
      python
      from collections.abc import Iterable, Iterator
      
      
      class IterObj:
      
          def __init__(self):
              self.a = [3, 5, 7, 11, 13, 17, 19]
      
          def __getitem__(self, i):
              return self.a[i]
      
      
      # 从创建对象
      it = IterObj()
      print(isinstance(it, Iterable))  # false
      print(isinstance(it, Iterator))  # false
      # <__main__.IterObj object at 0x0000000002573AC8>
      print(it)
      # # 
      print(iter(it))
      
      # 遍历
      for i in it:
          print(i)

    归纳:

    • 如果这个可迭代对象要在for循环中被使用,那么它就应该能够被内置的iter()函数调用并转化成Iterator对象。
    • Python的for语法功能非常强大,可以遍历任何可迭代的对象。

    参考:


    __EOF__

  • 本文作者: 繁华似锦的博客
  • 本文链接: https://www.cnblogs.com/liuyuelinfighting/p/15953720.html
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    【信号去噪】基于麻雀算法优化VMD实现信号去噪附matlab代码
    每天分享五款工具,让大家工作生活更顺心
    SSM2
    sqlserver问题
    String类 --- 上篇
    [附源码]SSM计算机毕业设计学生实习管理系统JAVA
    iPhone 15 Pro与iPhone 13 Pro:最大的预期升级
    Kotlin 开发Android app(十一):Android控件RecyclerView
    【Linux】vscode远程连接ubuntu,含失败解决方案
    Linux: IO中断驱动开发教程
  • 原文地址:https://www.cnblogs.com/liuyuelinfighting/p/15953720.html