python可迭代对象、迭代器、生成器


目录
  • 迭代器模式
    • 迭代器模式与yield关键字
    • python迭代器功能
  • 序列可以迭代的原因---iter函数
  • 可迭代对象与迭代器
    • 可迭代对象
    • 可迭代对象生成迭代器
    • 迭代器
    • 可迭代对象与迭代器对应的抽象基类
    • 迭代器定义
    • 不要把可迭代对象变成自身的迭代器
  • 生成器函数
    • 生成器函数定义
    • 生成器函数示例
    • 生成器函数内部工作机制
    • 生成器函数与return语句
    • 生成器表达式
    • 标准库中的生成器函数
      • 用于过滤的生成器函数
      • 用于映射的生成器函数
      • 用于合并的生成器函数
      • 用于扩展输入的可迭代对象的生成器函数
      • 用于重新排列元素的生成器函数
  • python3.3新句法:yield from
  • 可迭代的规约函数
  • iter函数深入分析

迭代器模式

迭代器模式与yield关键字

  • 扫描内存中放不下的数据集时,需要惰性获取数据,即按需一次获取一个数据项,这就是迭代器模式。
  • python为了实现迭代器模式,加入了yield关键字,用于构建生成器。
  • 所有生成器都是迭代器,因此生成器完全实现了迭代器接口。
  • 一般认为,迭代器用于从一个集合中取出元素,生成器则用于凭空生成元素,但在python中,一般将其视作同一概念。
  • python3中,即使时内置的range()函数也返回一个生成器对象,而在以前则返回完整的列表。
  • python中所有集合都是可迭代的。

python迭代器功能

  • for循环
  • 构建和扩展集合类型
  • 逐行遍历文本文件
  • 列表推导、字典推导和集合推导,本质还是for循环
  • 元组拆包
  • 调用函数时,使用 * 拆包实参

序列可以迭代的原因---iter函数

  • 解释器需要迭代对象x时,会自动调用iter(x):
    • 首先检查对象是否实现了__iter__方法,如果有,则调用它并返回一个迭代器。
    • 如果没有实现__iter__方法,但是实现了__getitem__方法,python会创建一个迭代器,尝试按索引顺序获取元素。
    • 若尝试失败,python抛出TypeError异常,提示 \(\times\times\times\) object is not iterable。
  • 任何序列均可迭代,是因为任何序列都要实现__getitem__方法。
  • 可以使用 isinstance(x, abc.Iterable)来判断对象x是否可迭代,但这种方式不准确,因为不会考虑__getitem__方法的存在。最好还是用iter(x)来判断,如果不抛出异常则可迭代。

可迭代对象与迭代器

可迭代对象

  • 使用内置函数iter可以获取迭代器的对象。如果对象实现了__iter__方法,则该对象是可迭代的。序列都是可迭代的。

可迭代对象生成迭代器

  1. 调用iter方法,传入一个可迭代对象,生成一个迭代器。
  2. 调用next(it)方法,传入迭代器,每次迭代一个元素。
  3. 当迭代器中元素耗尽,则抛出StopIteration异常。
  4. 废弃迭代器对象。
  • 这里是显示处理的StopIteration异常,python语言内部会自动处理for循环和其它迭代上下文中的StopIteration异常。

迭代器

  • 标准迭代器接口有两个方法
    • next,返回下一个可用的元素,若没有元素了,则抛出StopIteration异常。
    • iter,返回self,以便在该使用可迭代对象的时候使用迭代器,比如for循环中。

可迭代对象与迭代器对应的抽象基类

  1. gen_123是生成器函数,因为函数体中包含关键字yield。
  2. 生成器函数每次执行到yield就生成一个元素,因此生成器函数体中一般有循环,但是也可以没有,比如这里直接列出了三个yield语句用于三次生成。
  3. gen_123属于function类。
  4. 调用gen_123返回一个生成器对象。
  5. 生成器是迭代器,每次迭代都生成yield表达式生成的值。
  6. g是生成器对象。
  7. 生成器都是迭代器,可以调用next(g)获取下一个生成的元素。
  8. 生成器对象中元素耗尽后,抛出StopIteration异常。

生成器函数内部工作机制

  1. 调用生成器函数会生成一个生成器对象,包裹生成器函数的定义体。
  2. 把生成器对象传给next函数时,生成器函数向前执行,直到遇到第一个yield表达式,然后返回产出的值,并在当前位置暂停。
  3. 若元素未耗尽,继续执行,直到再次遇到yield表达式。
  4. 若元素耗尽,抛出StopIteration异常。

生成器函数与return语句

  • 生成器函数体中的return语句会触发生成器对象抛出StopIteration异常。
  • python3.3之前生成器函数体中不能有return语句。
  • 只有把生成器函数当作协程使用时,return语句才有意义。

生成器表达式

  • 生成器表达式是语法糖,完全可以替换成生成器函数,只是有时候生成器表达式更方便。

标准库中的生成器函数

用于过滤的生成器函数


用于映射的生成器函数

用于合并的生成器函数

用于扩展输入的可迭代对象的生成器函数

用于重新排列元素的生成器函数

python3.3新句法:yield from

  • 在chain生成器函数中,可迭代对象iterables中的元素it也是可迭代对象。

  • 对it用for循环和yield表达式来创建一个生成器,每次生成一个元素i。

  • 用yield from句法可以取代内层循环:

  • 使用yield from 后加上可迭代对象,可把可迭代对象中的元素一个一个yield出来,对比yield来说代码更简洁,不再使用循环来yield元素。

  • yield from并不是语法糖,其会创建通道,把内层生成器直接与外层客户端联系起来。把生成器当成协程使用时,此通道特别重要,不仅能为客户端代码生成器,还能使用客户端代码提供的值。

可迭代的规约函数

  • 归约函数都接收一个可迭代的对象,然后返回单个结果。
  • sorted函数
    内置函数sorted可以接收任意可迭代对象,且会构建并返回真正的列表,因此要读取可迭代对象中的每个元素才能排序,sorted不是生成器函数。

iter函数深入分析

  • iter函数可以使用任意可调用对象创建迭代器。需要传入两个参数,第一个参数是可调用对象,第二个参数是哨兵。不断调用第一个对象产出值,直到产出了哨兵就抛出异常。