在python中,所有集合都可以迭代,在python语言内部,迭代器用于支持

for循环

构建和扩展集合类型

逐行遍历文本文件

列表推导,字典推导和集合推导

元组拆包

调用函数时,使用*拆包实参

本章涵盖的话题

语言内部使用 iter(...) 内置函数处理可迭代对象的方式
如何使用 Python 实现经典的迭代器模式
详细说明生成器函数的工作原理
如何使用生成器函数或生成器表达式代替经典的迭代器
如何使用标准库中通用的生成器函数
如何使用 yield from 语句合并生成器
案例分析:在一个数据库转换工具中使用生成器函数处理大型数据集
为什么生成器和协程看似相同,实则差别很大,不能混淆

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

解释器需要迭代对象 x 时,会自动调用 iter(x)。
内置的 iter 函数有以下作用。
(1) 检查对象是否实现了 __iter__ 方法,如果实现了就调用它,获取一个迭代器。
(2) 如果没有实现 __iter__ 方法,但是实现了 __getitem__ 方法,Python 会创建一个迭
代器,尝试按顺序(从索引 0 开始)获取元素。
(3) 如果尝试失败,Python 抛出 TypeError 异常,通常会提示“C object is not iterable”(C
对象不可迭代),其中 C 是目标对象所属的类。

从 Python 3.4 开始,检查对象 x 能否迭代,最准确的方法是:调用 iter(x) 函
数,如果不可迭代,再处理 TypeError 异常。这比使用 isinstance(x,
abc.Iterable) 更准确,因为 iter(x) 函数会考虑到遗留的 __getitem__ 方法,
而 abc.Iterable 类则不考虑。

可迭代的对象与迭代器的对比

可迭代的对象
  使用 iter 内置函数可以获取迭代器的对象。如果对象实现了能返回迭代器的
__iter__ 方法,那么对象就是可迭代的。序列都可以迭代;实现了 __getitem__ 方
法,而且其参数是从零开始的索引,这种对象也可以迭代

>>> s = 'ABC'
>>> it = iter(s) # ➊
>>> while True:
... try:
... print(next(it)) # ➋
... except StopIteration: # ➌
... del it # ➍
... break # ➎
...
A
B
C

❶ 使用可迭代的对象构建迭代器 it。
❷ 不断在迭代器上调用 next 函数,获取下一个字符。
❸ 如果没有字符了,迭代器会抛出 StopIteration 异常。
❹ 释放对 it 的引用,即废弃迭代器对象。
❺ 退出循环。

StopIteration 异常表明迭代器到头了。Python 语言内部会处理 for 循环和其他迭代上
下文(如列表推导、元组拆包,等等)中的 StopIteration 异常。

标准的迭代器接口有两个方法。
__next__
  返回下一个可用的元素,如果没有元素了,抛出 StopIteration 异常。
__iter__
  返回 self,以便在应该使用可迭代对象的地方使用迭代器,例如在 for 循环中。

在 Python 3 中,Iterator 抽象基类定义的抽象方法是 it.__next__(),而
在 Python 2 中是 it.next()。一如既往,我们应该避免直接调用特殊方法,使用
next(it) 即可,这个内置的函数在 Python 2 和 Python 3 中都能使用。

查对象 x 是否为迭代器最好的方式是调用 isinstance(x, abc.Iterator)。得益

于 Iterator.__subclasshook__ 方法,即使对象 x 所属的类不是 Iterator 类的
真实子类或虚拟子类,也能这样检查

因为迭代器只需 __next__ 和 __iter__ 两个方法,所以除了调用 next() 方法,以及捕
获 StopIteration 异常之外,没有办法检查是否还有遗留的元素。此外,也没有办
法“还原”迭代器。如果想再次迭代,那就要调用 iter(...),传入之前构建迭代器的可
迭代对象。传入迭代器本身没用,因为前面说过 Iterator.__iter__ 方法的实现方式是
返回实例本身,所以传入迭代器无法还原已经耗尽的迭代器。

迭代器
  迭代器是这样的对象:实现了无参数的 __next__ 方法,返回序列中的下一个元素;
如果没有元素了,那么抛出 StopIteration 异常。Python 中的迭代器还实现了
__iter__ 方法,因此迭代器也可以迭代。

构建可迭代的对象和迭代器时经常会出现错误,原因是混淆了二者。要知道,可迭代的对
象有个 __iter__ 方法,每次都实例化一个新的迭代器;而迭代器要实现 __next__ 方
法,返回单个元素,此外还要实现 __iter__ 方法,返回迭代器本身。

因此,迭代器可以迭代,但是可迭代的对象不是迭代器。

可迭代的对象一定不能是自身的迭代器。也就是说,可迭代的对象必须实现
__iter__ 方法,但不能实现 __next__ 方法。

另一方面,迭代器应该一直可以迭代。迭代器的 __iter__ 方法应该返回自身。

生成器函数的工作原理
只要 Python 函数的定义体中有 yield 关键字,该函数就是生成器函数。调用生成器函数
时,会返回一个生成器对象。也就是说,生成器函数是生成器工厂。

生成器函数会创建一个生成器对象,包装生成器函数的定义体。把生成器传给
next(...) 函数时,生成器函数会向前,执行函数定义体中的下一个 yield 语句,返回
产出的值,并在函数定义体的当前位置暂停。最终,函数的定义体返回时,外层的生成器
对象会抛出 StopIteration 异常——这一点与迭代器协议一致。

何时使用生成器表达式

生成器表达式是创建生成器的简洁句法,这样无需先定义函数再调
用。不过,生成器函数灵活得多,可以使用多个语句实现复杂的逻辑,也可以作为协程
使用

选择使用哪种句法很容易判断:如果生成器表达式要分成多行写,我倾向
于定义生成器函数,以便提高可读性。此外,生成器函数有名称,因此可以重用。

使用itertools模块生成等差数列
Python 3.4 中的 itertools 模块提供了 19 个生成器函数,结合起来使用能实现很多有趣
的用法。

itertools.count 函数返回的生成器能生成多个数。如果不传入参
数,itertools.count 函数会生成从零开始的整数数列。不过,我们可以提供可选的
start 和 step 值

不过,itertools.takewhile 函数则不同,它会生成一个使用另一个生成器的生成器,
在指定的条件计算结果为 False 时停止。因此,可以把这两个函数结合在一起使用

标准库中的生成器函数

把生成器当成协程

与 .__next__() 方法一样,.send() 方法致使生成器前进到下一个 yield 语句。不
过,.send() 方法还允许使用生成器的客户把数据发给自己,即不管传给 .send() 方法
什么参数,那个参数都会成为生成器函数定义体中对应的 yield 表达式的值。也就是
说,.send() 方法允许在客户代码和生成器之间双向交换数据。而 .__next__() 方法只
允许客户从生成器中获取数据。

流畅的python第十四章可迭代的对象,迭代器和生成器学习记录的更多相关文章

  1. 流畅的python第十六章协程学习记录

    从句法上看,协程与生成器类似,都是定义体中包含 yield 关键字的函数.可是,在协程中,yield 通常出现在表达式的右边(例如,datum = yield),可以产出值,也可以不产出——如果 yi ...

  2. 流畅的python第十九章元编程学习记录

    在 Python 中,数据的属性和处理数据的方法统称属性(attribute).其实,方法只是可调用的属性.除了这二者之外,我们还可以创建特性(property),在不改变类接口的前提下,使用存取方法 ...

  3. 流畅的python第十五章上下文管理器和else块学习记录

    with 语句和上下文管理器for.while 和 try 语句的 else 子句 with 语句会设置一个临时的上下文,交给上下文管理器对象控制,并且负责清理上下文.这么做能避免错误并减少样板代码, ...

  4. 流畅的python第十二章继承的优缺点学习记录

    子类化内置类型的缺点 多重集成和方法解析顺序 tkinter

  5. 进击的Python【第十四章】:Web前端基础之Javascript

    进击的Python[第十四章]:Web前端基础之Javascript 一.javascript是什么 JavaScript 是一种轻量级的编程语言. JavaScript 是可插入 HTML 页面的编 ...

  6. python 教程 第十四章、 地址薄作业

    第十四章. 地址薄作业 #A Byte of Python #!/usr/bin/env python import cPickle import os #define the contacts fi ...

  7. Python 3标准库 第十四章 应用构建模块

    Python 3标准库 The Python3 Standard Library by  Example -----------------------------------------第十四章   ...

  8. 第十四章——循环神经网络(Recurrent Neural Networks)(第一部分)

    由于本章过长,分为两个部分,这是第一部分. 这几年提到RNN,一般指Recurrent Neural Networks,至于翻译成循环神经网络还是递归神经网络都可以.wiki上面把Recurrent ...

  9. 【odoo14】第十四章、CMS网站开发

    第十四章.CMS网站开发** Odoo有一个功能齐全的内容管理系统(CMS).通过拖放功能,你的最终用户可以在几分钟内设计一个页面,但是在Odoo CMS中开发一个新功能或构建块就不是那么简单了.在本 ...

随机推荐

  1. linux命令(5):netstat命令

    网络监控:netstat –in [显示所有配置接口的状态] 查看端口状态:netstat -anlp | grep 8080 [显示8080端口列出的监听状态] 查看某个进程软件名:netstat ...

  2. Linux和Windows双系统安装要点

    这里主要说下CentOS和Windows7的双系统安装遇到的一些问题 一.磁盘分区 这个不得不说下在Windows下坑爹的设定了,如果是用默认的磁盘划分,系统会自己先划出一个100M左右的区,关键还是 ...

  3. 利用js生成读取页面数据并导出为excel

    //核心,js部分 */var navs = new Vue({ el: '#navs', data: { navs: [] }, ready: function () { this.$http.ge ...

  4. Jenkins+maven+Tomcat配置发布

    jenkins大多数情况下都是用来部署Java项目,Java项目有一个特点是需要编译和打包的,一般情况下编译和打包都是用maven完成,所以系统环境中需要安装maven. 实验环境: 10.0.0.1 ...

  5. 9. Spark Streaming技术内幕 : Receiver在Driver的精妙实现全生命周期彻底研究和思考

        原创文章,转载请注明:转载自 听风居士博客(http://www.cnblogs.com/zhouyf/)       Spark streaming 程序需要不断接收新数据,然后进行业务逻辑 ...

  6. CodeForces 732F Tourist Reform

    边双连通分量. 这题有一点构造的味道.一个有向图,经过强连通缩点之后会形成一个有向无环图. 如果将最大的强连通分量放在顶端,其余的强连通分量都直接或间接指向他,那么这样就构造出了符合要求的图. 接下来 ...

  7. 性能测试篇:LoadRunner11 压力测试实例笔记

    最近在学习用loadrunner做web性能测试,简单记录一下一个自学实例流程. 1.录制测试脚本 (1).打开LR11,点击create/edit Script来打开VUgen (2).点击新建 ( ...

  8. NIO使用Reactor模式遇到的问题

    关于Reactor模式,不再多做介绍,推荐Doug Lea大神的教程:Java 可扩展的IO 本来在Reactor的构造方法中完成一系列操作是没有问题的: public class Reactor i ...

  9. Flask实战第67天:Flask+Celery实现邮件和短信异步发送

    之前在项目中我们发送邮件和 短信都是阻塞的,现在我们来利用Celery来优化它们 官方使用文档: http://flask.pocoo.org/docs/1.0/patterns/celery/ re ...

  10. LAMP搭建Discuz论坛

    搭建Discuz论坛 1.  准备LAMP环境 LAMP是Linux,Apache,MySql和PHP的缩写,是Discuz论坛系统依赖的基础运行环境 1.安装Apache2 Ubuntu需要安装Ap ...