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

调用生成器函数返回生成器; 生成器产出或生成值.

构建可迭代的对象和迭代器时经常会出现错误, 原因是混淆了二者。

要知道,可迭代的对象必须能从同一个可迭代的实例中获取多个独立的迭代器, 而且各个迭代器要能维护自身的内部状态,可迭代的对象有个 __iter__ 方法, 每次都实例化一个新的迭代器,而迭代器要实现 __next__ 方法, 返回单个元素, 此外还要实现__iter__ 方法, 返回迭代器本身。

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

可迭代的对象一定不能是自身的迭代器。 也就是说, 可迭代的对象必须实现 __iter__ 方法, 但不能实现 __next__ 方法。另一方面, 迭代器应该一直可以迭代。 迭代器的 __iter__ 方法应该返回自身。

比如字符串“hello world”是可迭代对象,对字符串调用iter方法(it = iter("hello world"))会返回一个迭代器 it, 迭代器it有__iter__方法和__next__方法,__next__方法放回下一个元素,__iter__方法返回迭代器本身。

虽然生成器函数看起来像函数, 可是我们不能通过简单的函数调用把职责委托给另一个生成器函数.Python 新引入的 yield from 句法允许生成器或协程把工作委托给第三方完成。

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

  协程使用生成器函数定义: 定义体中有 yield 关键字。

  yield 在表达式中使用; 如果协程只需从客户那里接收数据, 那么产出的值是 None——这个值是隐式指定的, 因为 yield 关键字右边没有表达式

  协程需要预激(next(gen) before gen.send(data))

在协程中, yield 碰巧( 通常) 出现在赋值语句的右手边, 因为 yield 用于接收客户传给 .send() 方法的参数。

仅当协程处于暂停状态的时候,才能使用send()发送值,如果协程还没有激活,则需要使用next(gen)进行激活(让协程向前执行到第一个 yield 表达式, 准备好作为活跃的协程使用),或者gen.send(None).

协程获取值的方法:

  1. 在协程中使用return,协程终止后,捕获StopIteration,StopIteration.value为return的值

  2. 使用yield from,对yield from 结构来说,解释器不仅会捕获 StopIteration 异常, 还会把 value 属性的值变成 yield from 表达式的值。yield from 结构会在内部自动捕获StopIteration 异常,这种处理方式与 for 循环处理 StopIteration异常的方式一样: 循环机制使用用户易于理解的方式处理异常。

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

yield from 结构的作用:

  替代产出值的嵌套 for 循环

  yield from 的主要功能是打开双向通道, 把最外层的调用方与最内层的子生成器连接起来, 这样二者可以直接发送和产出值, 还可以直接传入异常, 而不用在位于中间的协程中添加大量处理异常的样板代码。 有了这个结构, 协程可以通过以前不可能的方式委托职责。

因为委派生成器相当于管道, 所以可以把任意数量个委派生成器连接在一起: 一个委派生成器使用 yield from 调用一个子生成器, 而那个子生成器本身也是委派生成器, 使用 yield from 调用另一个子生成器, 以此类推。 最终, 这个链条要以一个只使用 yield表达式的简单生成器结束; 不过, 也能以任何可迭代的对象结束。

两种方法能避免阻塞型调用中止整个应用程序的进程:
  在单独的线程中运行各个阻塞型操作
  把每个阻塞型操作转换成非阻塞的异步调用使用

from:《Fluent Python》

python 可迭代对象与迭代器的更多相关文章

  1. Python可迭代对象、迭代器和生成器

    Python可迭代对象.迭代器和生成器 python 函数 表达式 序列 count utf-8 云栖征文 python可迭代对象 python迭代器 python生成器 摘要: 8.1 可迭代对象( ...

  2. python可迭代对象和迭代器和生成器

    可迭代对象 刚开始我认为这两者是等同的,但后来发现并不是这样:下面直接抛出结论: )可迭代对象包含迭代器. )如果一个对象拥有__iter__方法,其是可迭代对象:如果一个对象拥有next方法,其是迭 ...

  3. Python -- 可迭代对象和迭代器

    5.9 可迭代对象 可迭代对象: str , list , tuple , set , dict , range 1.在Python中,但凡内部有__iter__方法的对象,都是可迭代对象 2.查看对 ...

  4. 详解python可迭代对象、迭代器和生成器

    可迭代对象 什么是可迭代对象?顾名思义就是可以迭代的一个对象,再通俗点就是可以被for循环遍历的对象,如常用的list.str等数据类型.我们可以使用isinstance来判断这个数据是否是可迭代对象 ...

  5. python 可迭代对象,迭代器,生成器的区别及使用

    可迭代对象 可迭代对象类型:list,dict,tuple,str,set,deque等 如何判断一个对象是否是可迭代对象,可以通过dir()方法看它里面有没有__iter__方法,如果有这个方法就是 ...

  6. python 可迭代对象,迭代器和生成器,lambda表达式

    分页查找 #5.随意写一个20行以上的文件(divmod) # 运行程序,先将内容读到内存中,用列表存储. # l = [] # 提示:一共有多少页 # 接收用户输入页码,每页5条,仅输出当页的内容 ...

  7. Python可迭代对象和迭代器对象

    可迭代对象iterable: 对象字面意思:Python中一切皆对象.一个实实在在存在的值. 可迭代:更新迭代.迭代是一个重复的过程,每次重复是基于上一次的结果而继续的,每次都有新的内容. 可迭代对象 ...

  8. python(可迭代对象,迭代器,生成器及send方法详解)

    一.可迭代对象 对象必须提供一个__iter__()方法,如果有,那么就是可迭代对象, 像列表,元祖,字典等都是可迭代对象可使用isinstance(obj,Iterable)方法判断 from co ...

  9. python 可迭代对象与迭代器之间的转换

    列表: >>> l = [1, 2, 3, 4] >>> l_iter = iter(l) >>> l_iter <list_iterato ...

随机推荐

  1. HttpServletRequest接收参数的几种方法

    HttpServletRequest接收参数的几种方法 我们经常用servlet和jsp, 经常用request.getParameter() 来得到数据. request.getParameter( ...

  2. [UE4]装饰器:Blackboard(装饰器的一种,不是黑板)

    装饰器Blackboard可以检查黑板的值是否满足期望的条件: 添加“Blackboard装饰器”:在组合或者任务节点上右键“添加装饰器...”,跟普通装饰器一样. Notify Observer:通 ...

  3. c#类的继承与包含的关系

    基础例子 class Dept { private string name; private Emp emp; public string getName() { return this.name; ...

  4. Solr中的日期/时间表示

    摘要: Solr的日期字段(TrieDateField 和DateRangeField)可以对一个时间点以毫秒精度表示. 格式 Solr中的日期有很严格的格式限制: YYYY-MM-DDThh:mm: ...

  5. Navicat Premium 12.0.18 / 12.0.24安装与激活

    若使用Navicat Premium 12.1.8.0请转至Navicat Premium 12.1.8.0安装与激活,其实每个小版本更迭变化不大.另外最重要的是,请仔细阅读本文激活部分,总有一些人遇 ...

  6. Vuejs自定义全局组件--loading

    不管是使用框架,还是不使用任何的框架,我们都不可避免的需要与“加载中……”打交道,刚刚学习了Vuejs自定义组件的写法,就现学现卖,介绍一下吧! 先看一下目录结构,一般情况下,每一个组件都新建一个新的 ...

  7. VMware扩展Linux根目录磁盘空间(Centos版本)

    1.Centos 关机,选择编辑虚拟机设置,硬盘,在实用工具那里选择“扩展”,指定你需要的存储大小 2.启动客户机操作系统Centos,查看磁盘情况 输入指令 fdisk -l 显示结果如下 Disk ...

  8. Linux系统及常用软件的安装

    注释:看了很多人说在Windows下面跑机器学习就和大人一直用勺子吃饭一样,应该用更...刚写到这里Linux又奔溃了-- 以后就在Linux上跑程序了,告别Windows的时代... 别看下面的安装 ...

  9. django-chunks文件

    with open(file_save_path, 'wb') as f: for chunk in file_content.chunks(): f.write(chunk)

  10. [Unity基础]镜头管理类

    一个游戏中可能会有各种类型的镜头,例如有时候是第一人称,有时是第三人称,有时又会给个特写等等,因此可以定义一个镜头类型枚举,在不同的场合进行切换,管理起来很方便. CameraManager.cs u ...