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. tomcat启动出现乱码

    打开tomcat目录下apache-tomcat-9.0.26\conf\logging.properties 替换全文 encoding = UTF-8 为 encoding = GBK: rest ...

  2. js 混合排序(类似中文手机操作系统中的通讯录排序)

    在阳光明媚最适合打盹的下午, 特意静音的手机竟然动起来了, 你没看错, 它震动了.... 上帝(顾客)来电, "报表查询系统左侧树状菜单中设备的中文名称不能排序", 要增加排序功能 ...

  3. Hive之行转列与列转行

    行转列 原始数据: 需求: 把星座和血型一样的人归类到一起.结果如下: 射手座,A 大海|凤姐 白羊座,A 孙悟空|猪八戒 白羊座,B 宋宋 实现: vi person_info.txt 孙悟空 白羊 ...

  4. 后端(spring boot)解决跨区域问题

    一.环境: 前端 vue element-ui 后端:spring boot 工具:IDEA Maven Node 数据库:MySql 二.首先我们需要了解什么叫跨区域访问问题 跨区域访问是指:不同域 ...

  5. 关于WinForm TreeView的分享~

    最近在写个测试demo的时候使用到WinForm TreeView,已经好久没接触了,有些生疏,所以还是记录一下遇到的一些问题. 1.如果动态绑定TreeView,这个功能一般会在数据量不确定,需要去 ...

  6. 使用Storm实现累加求和操作

    package com.csylh; import org.apache.storm.Config; import org.apache.storm.LocalCluster; import org. ...

  7. Linux系统学习之Ln(软连接和硬链接)

    可简单理解为,软连接:创建的软连接文件是源文件的快捷方式,删除创建的软连接文件,源文件不受影响,连接消失. 硬链接:两个连体的文件,修改其中一个文件,另外一个文件也会随之更改:删除其中一个文件,另外一 ...

  8. java架构之路-(SpringMVC篇)SpringMVC主要流程源码解析(上)源码执行流程

    做过web项目的小伙伴,对于SpringMVC,Struts2都是在熟悉不过了,再就是我们比较古老的servlet,我们先来复习一下我们的servlet生命周期. servlet生命周期 1)初始化阶 ...

  9. PHP5.5 mysqli如何连接MySQL数据库和读取数据

    在学习 1. 开启PHP的API支持 (1)首先修改您的php.ini的配置文件.查找下面的语句:;extension=php_mysqli.dll将其修改为:extension=php_mysqli ...

  10. 30 分钟快速入门 Docker 教程

    原文地址:梁桂钊的博客 博客地址:http://blog.720ui.com 欢迎关注公众号:「服务端思维」.一群同频者,一起成长,一起精进,打破认知的局限性. 一.欢迎来到 Docker 世界 1. ...