yield关键字详解与三种用法
本篇文章比较硬核, 适合有一定Python基础的读者阅读, 如果您对Python还不甚了解可以先关注我哦, 我会持续更新Python技术文章
yield详解
yield与return相同每次调用都会返回一个值, 不同的是return返回值后会直接结束函数执行, 而yeild则是返回值后冻结函数执行, 下次调用此函数会从冻结处开始执行
(冻结就是保存函数状态, 所有的局部变量与执行状态都会被保留)
yield语法
send参数 yield 返回值
语法分为三个部分, 除yield关键字外其它两个部分全部可空
第一部分: yield表达式返回值 (send的参数), 从此处开始解除冻结
第二部分: yield关键字
第三部分: 返回值, 返回后从此处开始冻结
执行到yield时yield会把右边的表达式当做本次函数的返回值返回给调用者, 然后函数进入冻结状态, 再次调用被冻结函数时yield解除冻结, 如果本次调用使用的是send方法则yield会把调用send函数时传递的参数当做yield表达式的返回值
调用yield函数的四种方式 (执行迭代的四种方式)
首先先来了解几个概念
可迭代对象: 实现了 __iter__ 方法的对象就是可迭代对象 (生成迭代器的对象)
迭代器: __iter__ 方法返回的, 同时实现了 __iter__ 方法与 __next__ 方法的对象就是迭代器 (虽然只实现了 __next__ 方法就可以迭代, 但是它不是迭代器也不是可迭代对象也不是生成器…整个一三无产品, 所以最好不要使用这种语法)
生成器: 函数内使用了yield关键字, 调用这个函数返回的对象就是生成器, 生成器是一种特殊的迭代器 (元组推导式也可以创建生成器)
迭代器耗尽: 迭代器主动抛出了StopIteration异常, 就表示迭代器耗尽, Python会自动处理这个异常
(对可迭代对象调用iter内置函数将会创建一个迭代器)
(对迭代器执行next内置函数或调用send方法将执行一次迭代)
(生成器内置实现了 __iter__ 方法与 __next__ 方法)
1. next(生成器对象) – 内置函数, 执行一次迭代 (恢复冻结的生成器对象)
2. 生成器对象.send(yield表达式返回值) – 生成器方法, 传递参数并执行一次迭代 (恢复冻结的生成器对象) (必须先调用一次next全局函数后才能调用)
3. for循环 – 自动调用调用next全局函数进行迭代, 直到迭代器耗尽
4. list、tuple、str、set等序列对象会自动next全局函数进行迭代, 直到迭代器耗尽
1. 生成器
什么是生成器?
生成器是一种特殊的迭代器, 可以理解为生成元素的算法, 每次调用都会生成一个元素, 特点是不会占用很大的内存空间, 而是在需要时动态生成
使用yield实现range函数功能
# 使用yield实现range函数功能
def my_range(start, end=None, step=1):
if end is None:
start, end = 0, start
# 生成元素的算法
while start < end:
yield start
start += step
# 函数结束自动抛出StopIteration异常, 表示迭代器耗尽
# 使用list自动迭代
print(list(my_range(10)))
# 使用for循环迭代
for i in my_range(10):
print(i)
# 创建生成器对象
gen = my_range(10)
print(next(gen)) # 使用next内置函数执行一次迭代
print(gen.send(None)) # 使用send方法执行一次迭代
使用send方法改变生成器行为
# 定义一个无限生成器
def infinite():
i = 0
while True:
set_i = yield i # 使用set_i变量接收send传递的参数
if set_i is not None: # 没有send参数则yield表达式返回None
i = set_i
else:
i += 1
# 函数结束自动抛出StopIteration异常, 表示迭代器耗尽
# 创建生成器对象
gen = infinite()
2. 协程
什么是协程?
协程就是利用yield冻结特性来使多个函数交替执行, 使之呈现出并发执行效果 (多个函数同时执行)
(协程可以看做轻量级的线程, 优点是没有多线程的开销, 适用于IO密集型程序)
(这是最原始的协程实现方式, 实际开发中一般不会使用这种方式)
协程实现
def func_1():
while True:
print('--func1--') # 执行一部分代码
yield # 冻结, 等待下一次迭代唤醒
def func_2():
while True:
print('--func2--') # 执行一部分代码
yield # 冻结, 等待下一次迭代唤醒
# 创建生成器对象
func1 = func_1()
# 创建生成器对象
func2 = func_2()
# 循环执行
while True:
解除冻结, 执行一段代码冻结后返回
解除冻结, 执行一段代码冻结后返回
# 两个生成器交替冻结-解除冻结就完成了并发
# 效果就是单线程程序可以呈现出多线程效果
3. 上下文管理器
什么是上下文管理器?
上下文管理器保证了代码无论是否出现异常, 资源都会被正确回收
上文: 资源创建
下文: 资源释放 (无论是否出现异常都会被执行)
管理器: 上下文调度
上下文管理器可以通过实现 __enter__ 方法与 __exit__ 方法实现, 也可以使用函数+装饰器+yield实现, 本篇文章讲的就是函数+装饰器+yield的实现方式
上文由with语句开始时自动执行, 返回结果使用as关键字接收
下文由with语句结束时自动执行 (无论是否出现异常都会被执行)
函数+装饰器+yield 实现上下文管理器
# 导入上下文管理器装饰器
from contextlib import contextmanager
# 实现上下文管理器的文件对象
@contextmanager # 必须要使用contextmanager装饰器进行装饰
def m_file(filename, mode='r'):
# 上文 -- 创建外汇返佣打开文件 -- with开始时自动执行
f = open(filename, mode)
yield f # 返回上文对象 -- 对应__enter__方法 -- 返回值使用as关键字接收
# 下文 -- 关闭文件对象 -- with语句结束时自动执行
f.close() # 对应__exit__方法
# 使用with打开上下文管理器
with m_file('test.txt', 'w') as f:
f.write('test')
原文链接:https://blog.csdn.net/weixin_44221705/article/details/103572127
yield关键字详解与三种用法的更多相关文章
- Windows下图文详解PHP三种运行方式(php_mod、cgi、fastcgi)
PHP能不能成功的在Apache服务器上运行,就看我们如何去配置PHP的运行方式.PHP运行目前为止主要有三种方式: a.以模块加载的方式运行,初学者可能不容易理解,其实就是将PHP集成到Apache ...
- 详解django三种文件下载方式
推荐使用FileResponse,从源码中可以看出FileResponse是StreamingHttpResponse的子类,内部使用迭代器进行数据流传输. 在实际的项目中很多时候需要用到下载功能,如 ...
- 0108MySQL集群搭建详解(三种结点分离)
转自http://blog.csdn.net/yang1982_0907/article/details/20716845,感谢博主 本文将搭建一个最简化的MySQL Cluster系统,配置方法中的 ...
- MySQL集群搭建详解(三种结点分离)
本文将搭建一个最简化的MySQL Cluster系统,配置方法中的所有命令都是以root账户运行.这个MySQL Cluster包含一个管理结点.两个数据结点.两个SQL结点,这五个结点会分别安装在五 ...
- 详解数据库三种删除方法: delete drop truncate
Delete Delete :删除数据表中的行(可以删除某一行,也可以在不删除数据表的情况下删除所有行). 删除某一行:Delete from 数据表名称 where 列名称=值: 删除所有行:Del ...
- Java多线程(三)—— synchronized关键字详解
一.多线程的同步 1.为什么要引入同步机制 在多线程环境中,可能会有两个甚至更多的线程试图同时访问一个有限的资源.必须对这种潜在资源冲突进行预防. 解决方法:在线程使用一个资源时为其加锁即可. 访问资 ...
- RabbitMQ详解(三)------RabbitMQ的五种模式
RabbitMQ详解(三)------RabbitMQ的五种模式 1.简单队列(模式) 上一篇文章末尾的实例给出的代码就是简单模式. 一个生产者对应一个消费者!!! pom.xml 必须导入Rab ...
- .NET(c#)new关键字的三种用法
前几天去家公司面试,有一道这样的题:写出c#中new关键字的三种用法,思前想后挖空心思也只想出了两种用法,回来查了下msdn,还真是有第三种用法:用于在泛型声明中约束可能用作类型参数的参数的类型,这是 ...
- c# new关键字的三种用法
三种用法如下: 在 C# 中,new 关键字可用作运算符.修饰符或约束. 1)new 运算符:用于创建对象和调用构造函数. 2)new 修饰符:在用作修饰符时,new 关键字可以显式隐藏从基类继承的成 ...
随机推荐
- Unregistering JMX-exposed beans on shutdown解决方法:
Unregistering JMX-exposed beans on shutdown解决方法: 加入依赖如下: <dependency> <groupId>org.spr ...
- sql select语句详解
先group by 后 order by SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ] * | expression [ AS ...
- web服务器、WSGI跟Flask(等框架)之间的关系
之前对 Nginx,WSGI(或者 uWSGI,uwsgi),Flask(或者 Django),这几者的关系一存存在疑惑.通过查阅了些资料,总算把它们的关系理清了. 总括来说,客户端从发送一个 HTT ...
- Hive学习之路(三)Hive处理中文乱码
Hive注释中文乱码 创建表的时候,comment说明字段包含中文,表成功创建之后,中文说明显示乱码 create external table movie( userID int comment ' ...
- spring4.1.8扩展实战之六:注册bean到spring容器(BeanDefinitionRegistryPostProcessor接口)
本章是<spring4.1.8扩展实战>系列的第六篇,目标是学习如何通过自己写代码的方式,向spring容器中注册bean: 原文地址:https://blog.csdn.net/boli ...
- Oracle_管理控制文件和日志文件
控制文件: 控制文件在数据库创建时被自动创建,并在数据库发生物理变化时更新.控制文件被不断更新,并且在任何时候都要保证控制文件是可用的.只有Oracle进程才能安全地更新控制文件的内容,所以,任何时候 ...
- vue- 指令v-if 与指令v-show的区别
区别1: v-if :可以根据表达式的值在DOM中生成或移除一个元素. v-show:可以根据表达式的值来显示或者隐藏HTML元素.当v-show赋值为false时,元素被隐藏,此时查看代码时,该元素 ...
- 【ABAP系列】SAP ABAP模块-任意report作为附件以邮件形式发送
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP ABAP模块-任意rep ...
- POJ 3281 网络流 拆点保证本身只匹配一对食物和饮料
如何建图? 最开始的问题就是,怎么表示一只牛有了食物和饮料呢? 后来发现可以先将食物与牛匹配,牛再去和饮料匹配,实际上这就构成了三个层次. 起点到食物层边的容量是1,食物层到奶牛层容量是1,奶牛层到饮 ...
- MySQL 查询语句--------------进阶6:连接查询
#进阶6:连接查询 /* 含义:多个表格连接,当查询的字段来自于多个表时候,就会用到连接查询 我觉得这里类似于excel中的vlookup函数 笛卡尔乘积现象:表1有m行,表2有n行,结果有m*n行 ...