生成器:
生成器本身就是迭代器
创建生成器的两种方案:
1.生成器函数
2.生成器表达式
生成器函数:关键字yield
这里先来
def func():
print(123)
return 456
ret = func() # 执行func()函数,然后把return的值给ret,打印:123
print(ret) # 打印return返回值:456
生成器函数(生成器本身是可迭代的):
def func():
print(123)
yield 456 # 3.当函数中有yield,这个函数就是一个生成器函数,yield也有返回的意思
gen = func() # 1.这里什么都没有输出,因为这里只是创建了一个生成器函数
print(gen) # 2.打印:<generator object func at 0x019DBDF0> ,表示生成器在内存的地址
ret= gen.__next__() # 打印:123,next能让生成器执行到下一个yield,yield也有返回的意思,返回给next,得到一个返回值,我们赋值给ret
print(ret) # 这里打印yield返回的456
>>>
<generator object func at 0x034EBDF0>
123
456
一个函数有多个yield:
def func():
print(1111)
yield '第一个yield'
print(2222)
yield '第二个yield'
print(3333)
yield '第三个yield'
print('下面没有yield了')
gen = func() # 这里创建了个生成器,没有执行
r1 = gen.__next__() # 输出:111
print(r1) # 输出:第一个yield
r2 = gen.__next__() # 输出:2222
print(r2) # 输出:第二个yield
r3 = gen.__next__() # 输出:3333
print(r3) # 输出:第三个yield
r4 = gen.__next__() # 输出:下面没有yield了,然后报错:StopIteration,说不能迭代了(不能往下走了)
>>>
Traceback (most recent call last):
File "D:/pythonPLianxi1/python/20220221.py", line 20, in <module>
r4 = gen.__next__()
StopIteration
1111
第一个yield
2222
第二个yield
3333
第三个yield
下面没有yield了
Process finished with exit code 1
生成器总结:
1.里面有yield
2.生成器函数在执行的时候,实际上是创建一个生成器出来,不是执行生成器
3.必须使用__next__()来执行一段代码,会自动执行到下一个yield结束
4.yield也是返回的意思,可以让一个函数分段执行
5.当后面没有yield之后,再次__next__会报错StopIteration
生成器本身是非常省内存的
来个不省内存的
# 买10000件衣服
def order():
l = []
for i in range(100000): # 会比较耗资源
l.append(f'衣服{i}')
return l # 列表占内存 会感觉到电脑有点卡了,pycharm内存占用了1.5G
ls = order()
print(ls) # 输出:...'衣服99998', '衣服99999']
用yield执行:
yield是把代码放到内存中执行,要的时候再调用会从上次执行的下一行开始执行,通过分批执行能节省内存空间
# 生成器来做--分批拿衣服(什么时候要,什么时候拿,比较智能,省内存)
# 因为生成器在内存存储了这段代码 ,要用的时候拿出来调用一下
def order():
l= []
for i in range(10000):
l.append(f'衣服{i}')
if len(l) == 50: # 如果长度为50则返回
yield l
l = [] # 下次执行的之后清空列表,在上一行返回yield的时候代码停在那里,下次执行从这行开始
g = order()
l2= g.__next__()
print(l2)
# ['衣服0', '衣服1', '衣服........., '衣服47', '衣服48', '衣服49']
l3 = g.__next__()
print(l3)
# ['衣服50',......., '衣服97', '衣服98', '衣服99']
生成器本身也是迭代器:
1.省内存
2.惰性机制:找她要衣服才给我,不然不执行
3.只能往下执行,不能往回走
生成器的send:一般用不太到,了解下,send是要给yield进行赋值的
'''
__next__和send
相同点:
1.可以执行到下一个yield
不同点:
send:给上一个yield对应变量赋值
'''
def func():
print(111)
a = yield 'aaa'
print(222,a)
b = yield 'bbb'
print(333,b)
yield 'ccc'
g = func()
r1 = g.__next__() # 第一次执行必须用next,因为send是给上一个yield对应变量赋值,前面没有yield
print(r1)
r2 = g.send('这个嗯')
print(r2)
r3 = g.send('这里是哪里')
print(r3)
>>
111
aaa
222 这个嗯
bbb
333 这里是哪里
ccc