1 生成器
1.1 生成器的背景
迭代器的好处就是节省内存,而在某些情况下,我们也需要节省内存,就只能自己写。而我们自己写的这个实现迭代器功能的东西就是生成器
1.2 生成器的本质、特点
本质:迭代器(所以自带了__iter__方法和__next__方法,不需要我们去实现)
只要函数内部包含有yield关键字,那么函数名()的到的结果就是生成器,并且不会执行函数内部代码
特点:和迭代器的特点相同;惰性、节省内存、一步步执行
2 生成器函数
一个包含yield关键字的函数就是一个生成器函数。yield可以为我们从函数中返回值,但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。
生成器函数() -->获取的是生成器. 这个时候不执行函数
def func():
print("111")
yield 222
gener = func() # 这个时候函数不会执行. 而是获取到⽣成器
ret = gener.__next__() # 这个时候函数才会执行. yield的作用和return一样. 也是返回数据
2.1 yield和return的区别
yield是分段来执行一个函数. return呢? 直接停止执行函数.
send和__next__()区别:
(1) send和next()都是让生成器向下走一次
(2) send可以给上一个yield的位置传递值, 不能给后一个yield发送值. 在第一次执行生
成器代码的时候不能使用send()
2.2 生成器函数的执行方式获取数据
2.2.1 一个一个获取
2.2.1.1 __next__()
deffunc():print("111")yield 222
print("333")yield 444gener=func()
ret= gener.__next__()print(ret) #222
ret2 = gener.__next__()print(ret2) #333
ret3 = gener.__next__() #最后一个yield执行完毕. 再次__next__()程序报错,
print(ret3)
使用生成器. 一次就一个. 用多少生成多少. 生成器是一个一个的指向下一个. 不会回去, __next__()到哪, 指针就指到哪. 下一次继续获取指针指向的值
---->可以看出特点:一步一步向下执行,节省内存
2.2.1.2 Send()
Send()必须有参数,否则会报错
send() 和__next__()是一样的. 可以执行到下一个yield, 可以给上一个yield位置传值
# def func():
# print("我是第一个段")
# a =yield 123
# print(a)
# b = yield 456
# print(b) # ??
# print("赵一宁是第三段")
# c = yield 789
# print(c)
# print("刘伟是最后一个段")
# yield 79 # 最后收尾一定是yield
#
# g = func() #获取生成器
# print(g.__next__()) # 没有上一个yield 所以不能使用send() 开头必须是__next__()
# print(g.send("煎饼果子"))
# print(g.send("韭菜盒子"))
# print(g.send("锅包肉")) ## ??
2.2.2 一次性获取
List()、set()、str()、tuple()、for循环
3 推导式
3.1 列表、字典、集合推导式
lst =[]for i in range(1,15):
lst.append(i)print(lst)
替换成列表推导式:lst1 = [i fori inrange(1,15)]
print(lst1)
列表推导式是通过一行来构建你要的列表, 列表推导式看起来代码简单. 但是出现错误之
后很难排查.
列表推导式的常用写法:
[ 结果 for 变量 in 可迭代对象
判断条件]
3.2
生成器表达式
生成器表达式和列表推导式的区别:
(1)列表推导式比较耗内存. 一次性加载. 生成器表达式几乎不占用内存. 使用的时候才分 配和使用内存
(2)得到的值不一样. 列表推导式得到的是一个列表. 生成器表达式获取的是一个生成器.
生成器表达式和列表推导式的语法基本上是一样的. 只是把[]替换成()
gen = (i for i in range(10))print(gen)
结果: at 0x000001EFBA75EDB0>
# 寻找名字中带有两个e的人的名字
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'], ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
# 不用推导式和表达式
result =[]for first innames:for name infirst:if name.count("e") >= 2:
result.append(name)
# 推导式
gen = (name for first in names for name in first if name.count("e") >= 2)for name ingen:print(name)
4 生成器的惰性机制的详细解释
def add(a,b): #加法器
return a +bdef test(): #生成器
for i in range(4):yieldi
g=test() #获取生成器
for n in [1,10]: #这个for循环并未执行生成器,生成器执行的方式:__next__()、send()、list()等
g=(add(n,i) for i in g)#for循环执行完时,n=10,g=(add(n,i) for i in (add(n,i) for i in g))
#--->g=(add(10,i) for i in (add(10,i) for i in g))
print(g.__next__()) #20,此时才执行生成器的一步,指针就指向了这一步后
print(g.__next__()) #21,此时才执行生成器的一步,指针就指向了这一步后
print(list(g)) #[22,23]这一步是在上一步的基础上,把下面所有的步骤全部执行完,到此时生成器执行完
print(list(g)) #[],上面的生成器已经执行完毕,所以为空,list没有__next__()方法,所以没有StopIteration的报错
#结果显示[]