Python的生成器和生成器表达式
一,生成器和生成器表达式
什么是生成器,生成器实质就是迭代器,在python中有三种方式来获取生成器:
1. 通过生成器函数
和普通函数没有区别,里面有yield的函数就是生成器函数,生成器函数在执行的时候.,默认不会执行函数体.,返回生成器通过生成器的__next__()分段执行这个函数
send() 给上一个yield传值, 不能再开头(没有上一个yield), 最后一个yield也不可以用send()
先来看一下简单的函数
def xue(): #创建一个函数
print('学')
return 'Python' #生成器
xue1 = xue()
print(xue1)
结果:
学
Python
函数中的return换成yield这就是一个生成器
def xue():
print('学')
yield 'Python'
xue1 = xue()
print(xue1)
结果:
<generator object xue at 0x000002B7F1115660>
运行结果跟上面的不一样,因为由于函数中存在yield,那么这个函数就是一个生成器函数,这个时候我们在执行这个函数的时候,就不再是函数的执行了,而是获取这个生成器,如何使用呢?想想迭代器,生成器的本质就是迭代器,所以,我们可以直接执行__next__()来执行以下生成器
def xue():
print('学')
yield 'Python'
xue1 = xue() #这时候函数不会执行,而是获取到生成器
YJ = xue1.__next__()#这个时候函数才会执⾏行yield的作⽤用和return一样. 也是返回数据
print(YJ)
结果:
学
Python
yield和return的区别就是,yield是分段来执行一个函数,return是直接停止执行函数
def xue():
print('学')
yield 'Python'
print('也学')
yield 'java'
xue1 = xue() #这时候函数不会执行,而是获取到生成器
YJ = xue1.__next__()
print(YJ)
YJ1 = xue1.__next__()
print(YJ1)
YJ2 = xue1.__next__() #最后一个yield执行完毕,再次__next__()程序报错,也就是说和return无关了
print(YJ2)
结果:

当程序运行完最后一个yield,那么后面继续进行__next__()
需求:某学校要订购50000套校服,工厂直接生产50000套校服,但是学校也没有5000个学生,也没有教室放置一次性生产那么多,最后的效果会是什么呢?直接生产50000件校服,刷一下量大的话把你内存撑满!!!
def xiaofu():
lst = []
for el in range(0,50000):
lst.append('校服'+str(el))
return lst
xiaofu()
print(xiaofu())
我要一套你给一套,一共50000,是不是很完美
def xiaofu():
for el in range(0,50000):
yield '校服'+str(i)
xf = xiaofu()
print(xf.__next__())
print(xf.__next__())
print(xf.__next__())
print(xf.__next__())
两者的区别,第一种是直接一次性全部拿出来,会很占用内存,第二种是使用生成器,一次就一个,用多少生产多少,直到生产完,生成器是一个一个的指向下一个,不会回去,__next__()到哪,指针就指到哪儿,下一次继续获取指针指向的值
send方法,send和__next__()一样都可以让生成器执行到下一个yield
def xue():
print('要学')
a = yield 'Python'
print('a=',a)
b = yield 'java'
print('b=', b)
c = yield 'PHP'
print('c=', c)
yield 'YJ加油!'
xue1 = xue() #获取生成器
fh = xue1.__next__()
print(fh)
#结果:要学
# Python
fh1 = xue1.send('VB')
print(fh1)
# 结果:a= VB
# java
fh2 = xue1.send('C#')
print(fh2)
# 结果:b= C#
# PHP
fh3 = xue1.send('C++')
print(fh3)
# 结果:c= C++
# YJ加油!
send和__next__()的区别
1.send和next()都是让生成器向下走一次
2.send可以给上一个yield的位置传递值,不能给最后一个yield发送值,在第一次执行生成器代码的时候不能使用send()
生成器可以使用for需变换来循环获取内部元素:
def xue():
print('要学')
a = yield 'Python'
print('a=',a)
b = yield 'java'
print('b=', b)
c = yield 'PHP'
print('c=', c)
yield 'YJ加油!'
xue1 = xue()
for el in xue1:
print(el)
结果:

2. 通过各种推导式来实现生成器
1. 列表推导式 [结果 for循环 条件筛选]
2. 字典推导式 {k:v for循环 条件筛选}
3. 集合推导式 {k for循环 条件}
3. 通过数据的转换也可以获取生成器
二.,生成器表达式,列表推导式,以及其他推导式
我们来看一段代码,给出一个空列表,通过for循环向列表添加1-15个数字:
lst = []
for i in ramge(,):
lst.append(i)
print(lst)
结果:[, , , , , , , , , , , , , ,]
列表推导式写法:
#推导式
lst = [i for i in range(,)]
print(lst)
结果:[, , , , , , , , , , , , , , ]
两者的结果是不是一样?列表推导式比较简洁,列表推导式是通过一行来构建你要的列表,列表推导式看起来代码简单,但是出现错误之后就很难排查
列表推导式的写法:[结果 for 变量 in 可迭代对象]
需求:从1-19岁写入到lst列表中
lst = [str(i)+'岁' for i in range(,)]
print(lst)
结果:['1岁', '2岁', '3岁', '4岁', '5岁', '6岁', '7岁', '8岁', '9岁', '10岁', '11岁', '12岁', '13岁', '14岁', '15岁', '16岁', '17岁', '18岁', '19岁']
我们还可以对列表中的数据进行筛选,筛选写法:
[ 结果 for 变量 in 可迭代对象 if 条件 ]
#获取1-100内所有的偶数
lst = [i for i in range(1,100) if i % 2 ==0]
print(lst)
生成器表达式和列表推导式的语法基本是一样的,只是把[]换成()
YJ = (i for i in range(1,15))
print(YJ)
结果为:
<generator object <genexpr> at 0x000002CE3ABA5660>
上面的结果就是一个生成器,我们可以使用for循环来获取这个生成器
YJ = ('我今年%s岁了' % i for i in range(20))
for i in YJ:
print(i)
结果:
我今年0岁了
我今年1岁了
我今年2岁了
我今年3岁了
我今年4岁了
我今年5岁了
我今年6岁了
我今年7岁了
我今年8岁了
我今年9岁了
我今年10岁了
我今年11岁了
我今年12岁了
我今年13岁了
我今年14岁了
我今年15岁了
我今年16岁了
我今年17岁了
我今年18岁了
我今年19岁了
生成器表达式也是可以进行筛选的
获取1-100内能被3整除的数
# 获取1-100内能被3整除的数
YJ = (i for i in range(1,100) if i % 3 == 0)
print(YJ)
#结果:<generator object <genexpr> at 0x000002164AC95660>
for i in YJ: #使用for循环来循环这个生成器拿结果
print(i)
结果;
3,6,9,12,15...99
100以内能被3整除的数的平方
YJ = (i * i for i in range(100) if i % 3 == 0)
for i in YJ: #使用for循环来循环这个生成器拿结果
print(i)
生成器表达式跟列表推导式的区别:
1.列表推导式比较耗内存,一次性加载,生成器表达式几乎不占内存,使用的时候才分配和使用内存
2.得到的值不一样,列表推导式得到的是一个列表,生成器表达式获取的是一个生成器
生成器有惰性机制,生成器只有访问的时候才取值,说白了,你找它要它才会给你值,不找不给它也不会执行
字典推导式:
根据名字也能猜到,推到出来的是字典
dic = {'a' : 1, 'b' : 2, 'c' : 3}
dic1 = {dic[key] : key for key in dic}
print(dic1)
#结果:{1: 'a', 2: 'b', 3: 'c'}
集合推导式:
集合推导式可以帮我们直接生成一个集合,集合的特点是无序,不重复,所有集合推导式自带去重功能
lst = [1,1,2,3,3,66,66,8,9]
a = {abs(i) for i in lst}
print(a)
#结果:{1, 2, 3, 66, 8, 9}
总结:推导式有,列表推导式,字典推导式,集合推导式,切记切记!!!元组是没有推导式的
生成器表达式:(结果 for 变量量 in 可迭代对象 if 条件筛选)
生成器表达式可以直接获取到生成器对象,生成器对象可以直接进行for循环,生成器具有惰性机制!!!
2019年11月13日
Python的生成器和生成器表达式的更多相关文章
- python day12 ——1.生成器2.生成器表达式 3.列表推导式
一.生成器 什么是生成器. 生成器实质就是迭代器. 在python中有三种方式来获取生成器: 1. 通过生成器函数. 2. 通过各种推导式来实现生成器 . 3. 通过数据的转换也可以获取生成器. 1. ...
- Python学习笔记(4):容器、迭代对象、迭代器、生成器、生成器表达式
在了解Python的数据结构时,容器(container).可迭代对象(iterable).迭代器(iterator).生成器(generator).列表/集合/字典推导式(list,set,dict ...
- python全栈开发-前方高能-生成器和生成器表达式
python_day_13 今日主要内容1. 生成器和生成器函数生成器的本质就是迭代器生成器的三种创建办法: 1.通过生成器函数 2.通过生成器表达式创建生成器 3.通过数据转换 生成器函数: 函数中 ...
- Python入门-生成器和生成器表达式
昨天我们说了迭代器,那么和今天说的生成器是什么关系呢? 一.生成器 什么是生成器?说白了生成器的本质就是迭代器. 在Python中中有三种方式来获取生成器. 1.通过生成器函数 2.通过各种推导式来实 ...
- python 可迭代对象,迭代器和生成器,lambda表达式
分页查找 #5.随意写一个20行以上的文件(divmod) # 运行程序,先将内容读到内存中,用列表存储. # l = [] # 提示:一共有多少页 # 接收用户输入页码,每页5条,仅输出当页的内容 ...
- python的迭代器、生成器、三元运算、列表解析、生成器表达式
一 迭代的概念 迭代是Python最强大的功能之一,是访问集合元素的一种方式. 迭代器是一个可以记住遍历的位置的对象. 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前 ...
- 2018.8.13 python中生成器和生成器表达式
主要内容: 1.生成器和生成器函数 2.列表推导式 一.生成器 生成器是指就是迭代器,在python中有三种方式来获取生成器: 1.通过生成器函数 2.通过各种推导式来实现生成器 3.通过数据的转换也 ...
- python之序列去重以及生成器、生成器函数、生成器表达式与迭代器浅谈
首先要明确序列值类型是否可哈希,因为可哈希的值很简单就可以用 in /not in 写个生成器去判断,如果是不可哈希的就要去转换为可哈希的再用 in/not in 去判断 原地不可变类型(可哈希): ...
- python基础之生成器,三元表达式,列表生产式
生成器 1.什么是生成器? 在函数内但凡出现yield关键字,再调用函数就不会执行函数体代码,会返回一个值,该值称为生成器. 生成器的本质就是迭代器. 2.为什么要用生成器? 生成器是一种自定义迭代器 ...
随机推荐
- 201871010119-帖佼佼《面向对象程序设计(java)》第八周学习总结
博文正文开头格式:(2分) 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.co ...
- python学习-def1
# 4.可变参数\return# 可变参数:参数个数不固定 .调用的时候来确定有几个参数.# 第一种:*args 在函数内部,是以元组的形式来表示.def my_args(*args): # 放在位置 ...
- Python中最简单快捷的输出方式
格式化输出最简单的方式之哑巴填充公式 name=ludundun age=25 print(f'hello {name},your age is {age}') 输出内容: hello ludundu ...
- GHOST CMS - 配置 Config
Config For self-hosted Ghost users, a custom configuration file can be used to override Ghost's defa ...
- webpack构建原理和实现简单webpack
webpack打包原理分析 基础配置,webpack会读取配置 (找到入口模块) 如:读取webpack.config.js配置文件: const path = require("path& ...
- 内网渗透教程大纲v1.0
内网渗透 ☉MS14-068(CVE-2014-6324)域控提权利用及原理解析 ☉域控权限提升PTH攻击 未完待续...
- Android WebView 加载富文本内容
WebView加载数据的方式有两种: 1. webView.loadUrl(data);//加载url 2. webView.loadDataWithBaseURL(null,data, " ...
- 【译】gRPC vs HTTP APIs
本文翻译自 ASP.NET Blog | gRPC vs HTTP APIs,作者 James,译者 Edison Zhou. 写在开头 现在,ASP.NET Core使开发人员可以构建gRPC服务. ...
- js的动态表格的增删改查思路
1. 首先我们要知道,动态添加,肯定不是 在页面上写死得,而是通过js调用循环放入到页面上的,我们在写动态表格的时候不要先着急写,我们第一步要做的就是构思,要把自己的逻辑先弄清楚,不然的话,前面是好写 ...
- Docker安全扫描工具之docker-bench-security
简介 Docker Bench for Security检查关于在生产环境中部署Docker容器的几十个常见最佳实践.这些测试都是自动化的,其灵感来自CIS Docker基准1.2.0版. 这种安全扫 ...