1.生成器的本质就是迭代器
首先,我们先看一个函数:
def func():
print("111")
return 222
ret = func()
print(ret)
结果:
111
22
将函数的return替换成yield就是生成器:
def func():
print('111')
yield 222
ret = func()
print(ret)
结果:
<generator object func at
0x10567ff68>
运行的结果和上面的不一样,就是因为函数中存在了一个yield,那么这个函数就i是一个生成器函数
这个时候我们再执行这个函数的时候,就不再是函数的执行了,而是获取这个生成器
接下来如何使用呢?
想想迭代器,生成器的本质就是迭代器,所以,我们可以直接执行__next__()来执行以下的生成器:
def func():
print("111")
yield 222
gener = func() # 这个时候函数不会执行. 而是获取到生成器
ret = gener.__next__() # 这个时候函数才会执行. yield的作用和return一样. 也是返回数据
print(ret)
结果:
111
222
那么我们就可以看到,yield和return的效果是一样的.都可以返回值.
有什么区别呢?yield是分段来执行一个函数.return呢?直接停止执行函数
那么生成器有什么作用呢?
最简单的说就是节省内存
注意:生成器函数被执行. 获取到的是生成器. 而不是函数的执行
2.生成器的三种创建办法:
1.通过生成器函数
2.通过生成器表达式创建生成器
3.通过数据转换
3.send(值)和__next__()的区别:
send和next都是让生成器向下走一次
send可以给是上一个yield的位置传递值,不能给最后一个yield发送值,在第一次执行生成器代码的时候不能使用send
生成器可以使用for循环来循环获取内部的元素
取值:
1.
__next__()
2.
send(值)
给上一个yield位置传一个值, 第一个和最后一个yield不用传值
3.
可以for循环
4.
list(g)
4.生成器表达式:
(结果 for 变量 in 可迭代对象 if 筛选)
例如:
简单的来一个:给出一个列表,通过循环,向列表中添加1-15:
lst = []
for i in range(1-16):
lst.append(i)
print(lst)
按照之前的推倒式格式转换成下面代码:
lst = [i for i in range(1-16)]
print(lst)
列表推倒式是通过一行来构建你要的列表,列表推倒式看起来代码简单,但是出现错误后很难排查
筛选模式
[结果 for 变量 in 可迭代对象 if 条件]
lst = [i for i in range(1, 100)
if i % 2 == 0] # 获取100以内的所有偶数
生成器的表达式和列表的推倒式语法上基本上是一样的,就是把[]换成()
gen = (i for i in range(1, 100)
if i % 2 == 0)
print(gen)
这时候我们的到的结果是:
<generator object
<genexpr> at 0x106768f10>
打印的结果就是一个生成器,由此也可以看出生成器表达式可以进行筛选.
生成器表达式和列表推倒式的区别:
1.列表推倒式比较耗内存,一次性加载,生成器表达式几乎不占内存,使用的时候才分配和使用内存
2.得到是值不一样,列表推倒式得到是一个列表,生成器表达式获取的是一个生成器
生成器的惰性机制:
生成器之后再访问的时候才取值,说白了就是不找他要他才会给你值,不找他要,他是不会执行的
字典推倒式 {结果 for 变量 in 可迭代对象 if 筛选} 结果=>key:value
根据名字也不难看看出,就是推导出来的是字典
集合推倒式 {结果 for 变量 in 可迭代对象 if 筛选} 结果=>key
推导出来是集合,自带去重功能
总结:推倒式有,列表推倒式,字典推倒式,集合推倒式
元组是没有推倒式的.切记