生成器函数的工作原理
只要 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. 廖雪峰Java5集合-6Stack-1使用Stack

    1.栈的定义 栈Stack是一种后进先出(LIFO: Last In First Out)的数据结构,可以看作一端封闭的容器,先进去的元素永远在底部,最后出来. 栈有2个重要的方法: push(E e ...

  2. 廖雪峰Java4反射与泛型-3范型-4擦拭法

    1.擦拭法是Java泛型的实现方式. 编译器把类型视为Object. * 泛型代码编译的时候,编译器实际上把所有的泛型类型T统一视为Object类型.换句话说,虚拟机对泛型一无所知,所有的工作都是编译 ...

  3. 廖雪峰Java4反射与泛型-2注解-1使用注解

    1.Annotation定义 注解是放在Java源码的类.方法.字段.参数前的一种标签.如下 package com.reflection; import org.apache.logging.log ...

  4. Flume原理解析【转】

    一.Flume简介 flume 作为 cloudera 开发的实时日志收集系统,受到了业界的认可与广泛应用.Flume 初始的发行版本目前被统称为 Flume OG(original generati ...

  5. 1124 Raffle for Weibo Followers (20 分)

    1124 Raffle for Weibo Followers (20 分) John got a full mark on PAT. He was so happy that he decided ...

  6. [UE4]捡枪

    一.给角色添加碰撞胶囊体并添加On Component Begin Overlap事件 二.检查碰到的东西是不是武器 三.要捡的武器是否已经有主人.检查身上是否有同样类型的枪 五.把枪放到背包数组.关 ...

  7. 关于 MySQL LEFT JOIN 不可不知的事

    你认为自己已对 MySQL 的 LEFT JOIN 理解深刻,这篇文章,我想让你能多学会点东西! ON 子句与 WHERE 子句的不同 一种更好地理解带有 WHERE ... IS NULL 子句的复 ...

  8. Vue Admin 后台管理

    https://segmentfault.com/a/1190000009188689

  9. windows 查询文件被什么程序占用

    运行Resmon CPU选项卡全选 在[关联的句柄]里查询: 需要的时间挺多的...

  10. 如何跳过前端JavaScript的验证

    绕开前端的JS验证通常有以下的方法: 方法一: 将页面保存到自己机器上,然后把脚本检查的地方去掉,最后在自己机器上运行那个页面就可以了 方法二: 该方式与方法一类似一样,只是将引入js的语句删掉,或则 ...