生成器

作者: 上山走18398 | 来源:发表于2019-07-09 07:10 被阅读0次

概念

可以让函数生成一个序列(生成器对象),而不是一个值


一个生成器能暂停执行并返回一个中间的结果 —— 这就是 yield 语句的功能 : 返回一个中间值给调用者并暂停执行,交出控制权。



调用next()生成器函数一直运行到下一条yield语句为止(到yield暂时停止,下次从这开始)

yield n 实际是一个函数表达式,yield + 参数
m = yield n    m不等于n //调用next(),next返回参数n m的值一直为None,send(None)
next(), send()的返回值都是yield 后面的参数 n

send()是可以传递(yield表达式)的值进去--表达式的结果
m = yield n //m的值就为send(x)的参数x

而next()是发送一个None给(yield n)表达式     send(None)

换句话说,就是send可以强行修改上一个yield表达式值

 x = yield这个表达式的计算过程是先计算等号右边的内容,然后在进行赋值,所以当激活生成器后,程序会停在yield这里,但并没有给x赋值。

需要提醒的是,第一次调用时,请使用next()语句或是send(None),不能使用send发送一个非None的值,否则会出错的,因为没有yield语句来接收这个值。

启动生成器必须使用next()语句或是send(None)启动生成器,不能使用send发送一个非None的值

不管数据如何流动, yield 都是一种流程控制工具,使用它可以实现协作式多任务:协程可以把控制器让步给中心调度程序,从而激活其他的协程

关于调用next(...)函数这一步通常称为”预激(prime)“协程,即让协程向前执行到第一个yield表达式,准备好作为活跃的协程使用

协程

同步式的编程,通过生成器函数来实现类似异步的操作

协程库的运用,和内部实现机制

多线程,多进程 系统内部处理调用
协程: 人为的代码操作顺序流,在单线程中实现异步的感觉,所有说是在单线程中实现的,没有多线程和多进程实现会碰到的麻烦
只会有一点协程切换时的开销(如上下文环境的保存)

相当于一个函数中,调用非常多的子函数,协作式的完成一个主函数,不是抢占式(由系统判定和调用)

再加上一个事件驱动

无法利用多核,最好加上多进程,来提高运行

协程在运行过程中有四个状态:

GEN_CREATE:等待开始执行
GEN_RUNNING:解释器正在执行,这个状态一般看不到
GEN_SUSPENDED:在yield表达式处暂停
GEN_CLOSED:执行结束

预激协程的装饰器:预防 协程没有预先激发报错

关于预激,在使用yield from句法调用协程的时候,会自动预激活,这样其实与我们上面定义的coroutine装饰器是不兼容的,在python3.4里面的asyncio.coroutine装饰器不会预激协程,因此兼容yield from

yield from x 表达式对 x 对象所做的第一件事是,调用 iter(x),从中获取迭代器,因此, x 可以是任何可迭代的对象,这只是 yield from 最基础的用法==。

yield from 结构会自动捕获StopIteration异常,这种处理方式与for循环处理StopIteration异常的方式一样,循环机制使我们更容易理解处理异常,对于yield from来说,解释器不仅会捕获StopIteration异常,还会把value属性的值变成yield from表达式的值

eg.1

def gen():
     for c in "AB":
         yield c
     for i in range(1,3):
         yield i
 
 print(list(gen()))
 
 def gen2():
     yield from "AB"
     yield from range(1,3)
 
 print(list(gen2()))

协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。

每个协程表示一个执行单元,有自己的本地数据,与其它协程共享全局数据和其它资源。

协作式的任务,是要用户自己来负责任务的让出的。如果一个任务不主动让出,其他任务就不会得到调度

import inspect//检查类型库

线程有两个必须要处理的问题:
一是碰着阻塞式I\O会导致整个进程被挂起;
二是由于缺乏时钟阻塞,进程需要自己拥有调度线程的能力。

才能开始做数学作业。操作系统在切换进程或者线程时也是一样的,它需要先保存当前执行的现场环境(CPU寄存器状态、内存页等),
然后,把新任务的执行环境准备好(恢复上次的寄存器状态,切换内存页等),才能开始执行



必须在只有一个单线程里实现并发
修改共享数据不需加锁
用户程序里自己保存多个控制流的上下文栈
一个协程遇到IO操作自动切换到其它协程

yield from

yield from iterator
相当于
for x in iterator:
yield x

yield from用于重构生成器
yield from的作用还体现可以像一个管道一样将send信息传递给内层协程,并且处理好了各种异常情况

发展历程

1. 最初的生成器变形yield/send
2. 引入@asyncio.coroutine和yield from
3. 在最近的Python3.5版本中引入async/await关键字

总结

生成器是一种迭代器
python的迭代器是包含__next__ 方法的任何对象
迭代对象是任何定义了__iter__ 方法的对象。可迭代对象的__iter__ 方法负责返回一个迭代器

生成器:减少内存的占用,只关注当前值,而不用创建一个数组保留所有的数
内置函数使用生成器原理实现的机制
生成器交互 send()
send(),next() 返回的参数
yield xxx 表达式的返回值

yield from

事件循环,注册函数,监控FUTURE对象(包含协程的状态和result)

实现异步:减少I/O操作的等待

事件循环在这里将来自套接字(socket)的 I/O 已经准备好读和/或写作为“当A发生时”(通过selectors模块)
并发:一个CPU核,干很多事。感觉像是同时做很多事
并行:两个CPU核,干两件事

相关文章

  • 15.生成器generator

    目录:1.生成器介绍2.生成器举例3.生成器应用 1.生成器介绍 生成器指的是生成器对象,可以由生成器表达式得到,...

  • 2018-07-16

    ## 1\. 生成器和生成器函数 ``` 生成器的本质就是迭代器 生成器的三种创建办法: 1.通过生成器函数 ...

  • 第014篇:三大神器之生成器

    Python的三大神器:装饰器、迭代器、生成器 1、生成器 1.1、什么是生成器 生成器就是迭代器的一种;生成器作...

  • Python 生成器函数

    一、生成器 生成器指的是生成器对象,可由生成器表达式得到,也可使用 yield 关键字得到一个生成器函数,调用这个...

  • tornado协程的工作原理

    包含yield语句的函数是一个生成器。所有的生成器都是异步的。当我们调用生成器函数的时候,生成器函数返回一个生成器...

  • python 生成器小结

    作者:邵正将 来源:PytLab 在python中生成器可以很方便的实现迭代协议。生成器通过生成器函数产生,生成器...

  • ES6 Generators

    生成器函数 生成器函数以function*标注 yield关键字,会暂停生成器的执行,在之后可以继续执行 生成器的...

  • ES6 生成器Generator

    生成器 生成器(Generators): 一个更好的方法来构建遍历器。 --- 生成器和迭代器 生成器就是一类...

  • 生成器

    生成器指的是生成器对象,可以有生成器表达式获得,也可以由yield关键字得到一个生成器,调用这个函数得到一个生成器...

  • Python 入门之 Python三大器 之 生成器

    Python 入门之 Python三大器 之 生成器 1、生成器 (1)什么是生成器? 核心:生成器的本质就是一个...

网友评论

      本文标题:生成器

      本文链接:https://www.haomeiwen.com/subject/izqtkctx.html