百万年薪python之路 -- 生成器
1.生成器 #本质就是迭代器
1.1 生成器的构建方式
在python中有三种方式来创建生成器:
1.通过生成器函数
2.通过生成器推导式
3.python内置函数或者模块提供
1.2 生成器函数
我们先来研究通过生成器函数构建生成器。
def func():
print(11)
return 22
ret = func()
print(ret)
# 运行结果:
11
22
将函数中的return换成yield,这样func就不是函数了,而是一个生成器函数
def func():
print(11)
yield 22
我们这样写没有任何的变化,这是为什么呢? 我们来看看函数名加括号获取到的是什么?
def func():
print(11)
yield 22
ret = func()
print(ret)
# 运行结果:
<generator object func at 0x000001A575163888>
当我们调用函数的时候函数体里的代码会进行执行,当执行到yield的关键字的时候,发现我们是想声明一个生成器.程序就会返回一个生成器给我们
生成器的本质就是迭代器.迭代器如何取值,生成器就如何取值。所以我们可以直接执行next()或**_ _ next _ _()**方法来执行以下生成器
def func():
print("111")
yield 222
gener = func() # 这个时候函数不会执⾏. 而是获取到生成器
ret = next(gener) # 这个时候函数才会执行 推荐使用next()
#ret = gener.__next__() # 这个时候函数才会执行
print(ret) # 并且yield会将func生产出来的数据 222 给了 ret。
结果:
111
222
并且我的生成器函数中可以写多个yield。
def func():
print(11)
yield 22
print(33)
yield 44
print(func().__next__()) #启动了一个生成器
print(func().__next__()) #启动了另一个生成器
# 运行结果:
11
22
11
22
def func():
print("111")
yield 222
print("333")
yield 444
gener = func()
ret = gener.__next__()
print(ret)
ret2 = gener.__next__()
print(ret2)
ret3 = gener.__next__()
# 最后⼀个yield执⾏完毕. 再次__next__()程序报错 StopIteration异常
print(ret3)
当程序运行完最后一个yield,那么后面继续运行next()程序会报错,一个yield对应一个next,next超过yield数量,就会报错,与迭代器一样。
yield与return的区别:
return一般在函数中只设置一个,他的作用是终止函数,并且给函数的执行者返回值。
yield在生成器函数中可设置多个,他并不会终止函数,next会获取对应yield生成的元素。
应用场景:
我们来看一下这个需求:老男孩向楼下卖包子的老板订购了10000个包子.包子铺老板非常实在,一下就全部都做出来了
def eat():
lst = []
for i in range(1,10000):
lst.append('包子'+str(i))
return lst
e = eat()
print(e)
这样做没有问题,但是我们由于学生没有那么多,只吃了2000个左右,剩下的8000个,就只能占着一定的空间,放在一边了。如果包子铺老板效率够高,我吃一个包子,你做一个包子,那么这就不会占用太多空间存储了,完美。
def eat():
for i in range(1,10000):
yield '包子'+str(i)
e = eat()
for i in range(200):
next(e)
这两者的区别:
第一种是直接把包子全部做出来,占用内存。
第二种是吃一个生产一个,非常的节省内存,而且还可以保留上次的位置。
def eat():
for i in range(1,10000):
yield '包子'+str(i)
e = eat()
for i in range(200):
next(e)
for i in range(300):
next(e)
# 多次next包子的号码是按照顺序记录的。
1.3 send 方法(了解)
接下来我们再来认识一个新的东西,send方法
# next只能获取yield生成的值,但是不能传递值。
def gen(name):
print(f'{name} ready to eat')
while 1:
food = yield
print(f'{name} start to eat {food}')
g = gen('alex')
next(g)
next(g)
next(g)
# 而使用send这个方法是可以的。
def gen(name):
print(f'{name} ready to eat')
while 1:
food = yield 222
print(f'{name} start to eat {food}')
g = gen('alex')
next(g) # 第一次必须用next让指针停留在第一个yield后面
# 与next一样,可以获取到yield的值
ret = g.send('骨头')
print(ret)
结果:
alex ready to eat
alex start to eat 骨头
222
def gen(name):
print(f'{name} ready to eat')
while 1:
food = yield
print(f'{name} start to eat {food}')
g = gen('alex')
next(g)
# 还可以给上一个yield发送值
g.send('骨头')
g.send('狗粮')
g.send('香肠')
send和next()区别:
相同点:
send 和 next()都可以让生成器对应的yield向下执行一次。
都可以获取到yield生成的值。
不同点:
第一次获取yield值只能用next不能用send( 可以用send(None) )。
send可以给上一个yield置传递值。
1.4 yield from
在python3中提供一种可以直接把可迭代对象中的每一个数据作为生成器的结果进行返回
# 对比yield 与 yield from
def func():
lst = ['卫龙','老冰棍','北冰洋','牛羊配']
yield lst
g = func()
print(g)
print(next(g)) # 只是返回一个列表
结果:
<generator object func at 0x0000018C18AB94F8>
['卫龙', '老冰棍', '北冰洋', '牛羊配']
def func():
lst = ['卫龙','老冰棍','北冰洋','牛羊配']
yield from lst
g = func()
print(g)
# 他会将这个可迭代对象(列表)的每个元素当成迭代器的每个结果进行返回。
print(next(g))
print(next(g))
print(next(g))
print(next(g))
结果:
<generator object func at 0x00000213E7D194F8>
卫龙
老冰棍
北冰洋
牛羊配
'''
yield from ['卫龙','老冰棍','北冰洋','牛羊配']
等同于:
yield '卫龙'
yield '老冰棍'
yield '北冰洋'
yield '牛羊配'
1.5 yield from 小坑
def func():
lst1 = ['卫龙', '老冰棍', '北冰洋', '牛羊配']
lst2 = ['馒头', '花卷', '豆包', '大饼']
yield from lst1
yield from lst2
g = func()
for i in g:
print(i)
结果:
卫龙
老冰棍
北冰洋
牛羊配
馒头
花卷
豆包
大饼
返回的结果是将第一个列表的元素全部返回后,在返回第二个列表
百万年薪python之路 -- 生成器的更多相关文章
- 百万年薪python之路 -- 并发编程之 协程
协程 一. 协程的引入 本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质:切换+保存状态 cpu正在运行一个任务,会在两 ...
- 百万年薪python之路 -- 面向对象之 反射,双下方法
面向对象之 反射,双下方法 1. 反射 计算机科学领域主要是指程序可以访问.检测和修改它本身状态或行为的一种能力(自省) python面向对象中的反射:通过字符串的形式操作对象相关的属性.python ...
- 百万年薪python之路 -- 面向对象之继承
面向对象之继承 1.什么是面向对象的继承 继承(英语:inheritance)是面向对象软件技术当中的一个概念. 通俗易懂的理解是:子承父业,合法继承家产 专业的理解是:子类可以完全使用父类的方法和属 ...
- 百万年薪python之路 -- 数据库初始
一. 数据库初始 1. 为什么要有数据库? 先来一个场景: 假设现在你已经是某大型互联网公司的高级程序员,让你写一个火车票购票系统,来hold住十一期间全国的购票需求,你怎么写? 由于在同一时 ...
- 百万年薪python之路 -- 内置函数练习
1.整理今天笔记,课上代码最少敲3遍. 2.用列表推导式做下列小题 过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母 lst = [["a","b"],[ ...
- 百万年薪python之路 -- 推导式
2.1列表推导式 首先我们先看一下这样的代码,给出一个列表,通过循环,想列表中添加1~10: li = [] for i in range(1,11): li.append(i) print(li) ...
- 百万年薪python之路 -- JS基础介绍及数据类型
JS代码的引入 方式1: <script> alert('兽人永不为奴!') </script> 方式2:外部文件引入 src属性值为js文件路径 <script src ...
- 百万年薪python之路 -- 前端CSS样式
CSS样式 控制高度和宽度 width宽度 height高度 块级标签能设置高度和宽度,而内联标签不能设置高度和宽度,内联标签的高度宽度由标签内部的内容来决定. 示例: <!DOCTYPE ht ...
- 百万年薪python之路 -- MySQL数据库之 Navicat工具和pymysql模块
一. IDE工具介绍(Navicat) 生产环境还是推荐使用mysql命令行,但为了方便我们测试,可以使用IDE工具,我们使用Navicat工具,这个工具本质上就是一个socket客户端,可视化的连接 ...
随机推荐
- RDDs之combineByKey()
combineByKey(crateCombiner,mergeValue,mergeCombiners,partitioner) 最常用的基于Key的聚合函数,返回的类型可以和输入的类型不一样 许多 ...
- JavaScript之对象Array
数组Array是JavaScript中最常用的类型之一,同一数组中可以保存任意类型的数据,并且它的长度是动态的,会随着数组中数据的加减自动变化.每个数组都有一个表示其长度(数组元素的个数)的lengt ...
- jvm对象内存分配
一.jvm简单结构图 1.jvm内存对象分配整体流程: 1.类加载子系统和方法区 类加载子系统负责从文件系统或者网络中加载Class信息,加载的类信息存放于一块称为方法区的内存空间.除了类的信息外, ...
- 使用Shell脚本编译运行C++源码 输入输出重定向
在写C++控制台程序的时,如果使用Xcode或者Visual Studio之类的IDE,需要创建许多工程,会造成很多不便.有时,采用Vim或者Sublime text等编辑器编写简单的控制台程序能节省 ...
- Spring Boot 配置元数据指南
1. 概览 在编写 Spring Boot 应用程序时,将配置属性映射到 Java bean 上是非常有用的.但是,记录这些属性的最好方法是什么呢? 在本教程中,我们将探讨 Spring Boot C ...
- js---电商中常见的放大镜效果
js中的放大镜效果 在电商中,放大镜效果是很常见的,如下图所示: 当鼠标悬浮时,遮罩所在区域在右侧进行放大. 在动手写之前,我们要先理清思路,分析需求,所需知识点,再将每一块进行组装,最后进行功能的完 ...
- 完美激活Pycharm2019.2.3专业版
完美激活Pycharm2019.2.3专业版 Pycharm官网自9月11更新到pycharm2019.2.2版本后,在短短的2周时间与9月25又带来新版本2019.2.3,不可说更新不快,侧面可以看 ...
- 如何设置eclipse自动提示功能
1.Window --> preferences 2.java --> Editor --> Content Assist 3.将Auto activation triggers f ...
- ueditor的初始化赋值
ue.ready(function () {ue.setContent('初始内容'); //赋值给UEditor });
- Step ‘Publish JUnit test result report’ failed: No test report files were found问题解决
1. 查看配置 2.路径设置错误,修改路径和path一致即可 修改后的测试报告路径 重新构建成功