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之路 -- 生成器的更多相关文章

  1. 百万年薪python之路 -- 并发编程之 协程

    协程 一. 协程的引入 本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质:切换+保存状态 cpu正在运行一个任务,会在两 ...

  2. 百万年薪python之路 -- 面向对象之 反射,双下方法

    面向对象之 反射,双下方法 1. 反射 计算机科学领域主要是指程序可以访问.检测和修改它本身状态或行为的一种能力(自省) python面向对象中的反射:通过字符串的形式操作对象相关的属性.python ...

  3. 百万年薪python之路 -- 面向对象之继承

    面向对象之继承 1.什么是面向对象的继承 继承(英语:inheritance)是面向对象软件技术当中的一个概念. 通俗易懂的理解是:子承父业,合法继承家产 专业的理解是:子类可以完全使用父类的方法和属 ...

  4. 百万年薪python之路 -- 数据库初始

    一. 数据库初始 1. 为什么要有数据库? ​ 先来一个场景: ​ 假设现在你已经是某大型互联网公司的高级程序员,让你写一个火车票购票系统,来hold住十一期间全国的购票需求,你怎么写? 由于在同一时 ...

  5. 百万年薪python之路 -- 内置函数练习

    1.整理今天笔记,课上代码最少敲3遍. 2.用列表推导式做下列小题 过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母 lst = [["a","b"],[ ...

  6. 百万年薪python之路 -- 推导式

    2.1列表推导式 首先我们先看一下这样的代码,给出一个列表,通过循环,想列表中添加1~10: li = [] for i in range(1,11): li.append(i) print(li) ...

  7. 百万年薪python之路 -- JS基础介绍及数据类型

    JS代码的引入 方式1: <script> alert('兽人永不为奴!') </script> 方式2:外部文件引入 src属性值为js文件路径 <script src ...

  8. 百万年薪python之路 -- 前端CSS样式

    CSS样式 控制高度和宽度 width宽度 height高度 块级标签能设置高度和宽度,而内联标签不能设置高度和宽度,内联标签的高度宽度由标签内部的内容来决定. 示例: <!DOCTYPE ht ...

  9. 百万年薪python之路 -- MySQL数据库之 Navicat工具和pymysql模块

    一. IDE工具介绍(Navicat) 生产环境还是推荐使用mysql命令行,但为了方便我们测试,可以使用IDE工具,我们使用Navicat工具,这个工具本质上就是一个socket客户端,可视化的连接 ...

随机推荐

  1. 【linux】【maven】maven及maven私服安装

    前言 系统环境:Centos7.jdk1.8 私服是一种特殊的远程仓库,它是架设在局域网内的仓库服务,私服代理广域网上的远程仓库,供局域网内的用户使用.当Maven需要下载构件的时候,它从私服请求,如 ...

  2. [转]Linux下 tar.xz格式文件的解压方法

    现在很多找到的软件都是tar.xz的格式的,xz 是一个使用 LZMA压缩算法的无损数据压缩文件格式. 和gzip与bzip2一样,同样支持多文件压缩,但是约定不能将多于一个的目标文件压缩进同一个档案 ...

  3. layDate——设置最大日期不能超过当前日期

    例如,当前年份是2018年,实现效果如下,2018年之后年份不可操作: 具体代码实现: layui.use([ 'laydate'], function () { var laydate = layu ...

  4. 魔鬼在细节,理解Java并发底层之AQS实现

    jdk的JUC包(java.util.concurrent)提供大量Java并发工具提供使用,基本由Doug Lea编写,很多地方值得学习和借鉴,是进阶升级必经之路 本文从JUC包中常用的对象锁.并发 ...

  5. Python3 Linux安装(Redhat)

    Python3 Linux安装(Redhat): 下载Python-3.6.4.tgz: https://www.python.org/downloads/release/python-364/  Y ...

  6. ELK 学习笔记之 Logstash基本语法

    Logstash基本语法: 处理输入的input 处理过滤的filter 处理输出的output 区域 数据类型 条件判断 字段引用 区域: Logstash中,是用{}来定义区域 区域内,可以定义插 ...

  7. Scala 学习笔记之集合(4)

    集合的模式匹配操作: object CollectionDemo5 { def main(args: Array[String]): Unit = { //集合模式匹配1 val ls = List( ...

  8. Spring Cloud Config Server 节点迁移引起的问题,请格外注意这一点!

    前言: 虽然强烈推荐选择使用国内开源的配置中心,如携程开源的 Apollo 配置中心.阿里开源的 Nacos 注册&配置中心. 但实际架构选型时,根据实际项目规模.业务复杂性等因素,有的项目还 ...

  9. Rust到底值不值得学--Rust对比、特色和理念

    前言 其实我一直弄不明白一点,那就是计算机技术的发展,是让这个世界变得简单了,还是变得更复杂了. 当然这只是一个玩笑,可别把这个问题当真. 然而对于IT从业者来说,这可不是一个玩笑.几乎每一次的技术发 ...

  10. Java基础学习(八) - 多线程

    理解线程 进程是指一个内存中运行的应用程序,系统运行一个程序即是一个进程从创建,运行,结束的过程. 线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程. 多线程的特点是并发 ...