https://www.cnblogs.com/luchuangao/articles/6685626.html
import time
def test():
print('开始生孩子啦。。。。。。')
print('开始生孩子啦。。。。。。')
print('开始生孩子啦。。。。。。')
yield '我' #return
time.sleep(3)
print('开始生儿子啦')
yield '儿子'
time.sleep(3)
print('开始生孙子啦')
yield '孙子'
#
res=test()
print(res)
print(res.__next__()) #test() 生成器基于迭代器协议 会保留函数的状态 下次接着运行下个yield
print(res.__next__()) #test()
print(res.__next__()) #test()
输出
<generator object test at 0x00000000026F92B0>
开始生孩子啦。。。。。。 1
开始生孩子啦。。。。。。 1
开始生孩子啦。。。。。。 1
我 1
开始生儿子啦 2
儿子 2
开始生孙子啦 3
孙子 3
def product_baozi():
ret=[]
for i in range(100):
ret.append('一屉包子%s' %i) #要完整产生一个列表 类似包子全都做完放到一起,然后才卖,效率不高
return ret
baozi_list=product_baozi()
print(baozi_list)
def product_baozi():
for i in range(100):
print('正在生产包子')
yield '一屉包子%s' %i #i=1 并不需要完整产生一个列表,要一个取一个
print('开始卖包子')
pro_g=product_baozi()
baozi1=pro_g.__next__()
print('来了一个人吃包子',baozi1)
#加代码
baozi1=pro_g.__next__()
print('来了一个人吃包子',baozi1)
输出
正在生产包子
来了一个人吃包子 一屉包子0
开始卖包子
正在生产包子
来了一个人吃包子 一屉包子1
def xiadan():
ret=[]
for i in range(10000):
ret.append('鸡蛋%s' %i)
return ret
print(xiadan())
缺点1:占空间大
缺点2:效率低
def xiadan():
for i in range(5):
yield '鸡蛋%s' %i #下一个给一个,不占过多内存
alex_lmj=xiadan()
print(alex_lmj.__next__())
print(alex_lmj.__next__())
print(alex_lmj.__next__())
print(alex_lmj.__next__())
print(alex_lmj.__next__())
print(alex_lmj.__next__())
for jidan in alex_lmj:
print(jidan)
jidan=alex_lmj.__next__()
jidan=alex_lmj.__next__()
jidan=alex_lmj.__next__()
jidan=alex_lmj.__next__()
jidan=alex_lmj.__next__()
jidan=alex_lmj.__next__()
print('zhoushaochen 取鸡蛋',jidan)
综上已经对生成器有了一定的认识,下面我们以生成器函数为例进行总结
- 语法上和函数类似:生成器函数和常规函数几乎是一样的。它们都是使用def语句进行定义,差别在于,生成器使用yield语句返回一个值,而常规函数使用return语句返回一个值
- 自动实现迭代器协议:对于生成器,Python会自动实现迭代器协议,以便应用到迭代背景中(如for循环,sum函数)。由于生成器自动实现了迭代器协议,所以,我们可以调用它的next方法,并且,在没有值可以返回的时候,生成器自动产生StopIteration异常
- 状态挂起:生成器使用yield语句返回一个值。yield语句挂起该生成器函数的状态,保留足够的信息,以便之后从它离开的地方继续执行
优点一:生成器的好处是延迟计算,一次返回一个结果。也就是说,它不会一次生成所有的结果,这对于大数据量处理,将会非常有用。
1 #列表解析
2 sum([i for i in range(100000000)])#内存占用大,机器容易卡死
3
4 #生成器表达式
5 sum(i for i in range(100000000))#几乎不占内存
生成器只能遍历一次, 母鸡下完蛋就死了
各省人口占比
def get_polulation(): #特定功能,写成函数形式
with open('人口普查', 'r', encoding='utf-8') as f:
for i in f:
yield i #比ret.append(i)更快用内存更少
g=get_polulation()
print(g.__next__()) #{'name':'北京','population':10}
g=get_polulation()
g.__next__()
g.__next__()
g.__next__()
g.__next__()
print(g.__next__()['population']) #不行,字符串字符串必须通过整型来取,g.__next__()实际上不是字典,而是长成字典样子的字符串,要转成字典
s1=eval(g.__next__()) #eval把字符串里面的表达式运算出来,以及字符串里面的格式表达出来,
print(type(s1)) #<class 'dict'> 成功转成字典
print(s1['population']) #1000000 成功取到数据
res=0
for p in g:
p_dic=eval(p) #取出某一行的字典样子的字符串转换成字典
print(p_dic['population']) #显示字典中population的value
res+=p_dic['population']
print(res)
# 等效
all_pop=sum(eval(i)['population'] for i in g) #for i in g eval(i)['population'] 转成字典后取popula求和
print(all_pop)
#
无用 生成器只能遍历一次, 母鸡下完蛋就死了
for p in g:
print('%s %%' %eval(p)['population']/all_pop) #没有输出啊,因为前边 for i in g已经历遍了文件,
# 导致光标已经是在最后了,已经没有数据可以给我们了,
# 如果想要保留数据的话要在next函数那里给赋值来记录下来
生产消费模型
import time
def producer(): #生产包子,全生产后操作
ret=[]
for i in range(100):
time.sleep(0.1)
ret.append('包子%s' %i)
return ret
def consumer(res):
for index,baozi in enumerate(res): #enumerate输出索引 和内容‘包子n’
time.sleep(0.1)
print('第%s个人,吃了%s' %(index,baozi))
res=producer() #拿到100个包子list
consumer(res) #循环包子
用生成器改写
yield 3相当于r eturn 控制的是函数的返回值
x=yield的另外一个特性,接受send传过来的值,赋值给x
def test():
print('开始啦')
firt=yield 1#return 1 first='sbsbsb' 'sbsbsb'是t.send('sbsbsb')中的'sbsbsb'
print('第一次',firt)
yield 2
print('第二次')
t=test() #这一步还没有开始运行,只执行这一步的话不会有print
print(t) #拿到生成器对象 <generator object test at 0x00000000028F8200>
res=t.__next__() #next(t) 这两种方法
print(res)
res=t.send('sbsbsb') #第三种方法触发生成器 从光标位置的yield执行到下一个yield,
并且将括号内的'sbsbsb'值赋值给函数中的firt=yield 1 中的firt
# res=t.send('函数停留在first那个位置,我就是给first赋值的')
print(res)
def producer():
ret=[]
for i in range(100):
time.sleep(0.1)
ret.append('包子%s' %i)
return ret
def consumer(name):
print('我是[%s],我准备开始吃包子了' %name)
while True:
baozi=yield
time.sleep(1)
print('%s 很开心的把【%s】吃掉了' %(name,baozi))
def producer():
c1=consumer('wupeiqi')
c2=consumer('yuanhao_SB')
c1.__next__()
c2.__next__()
for i in range(10):
time.sleep(1)
c1.send('包子 %s' %i)
c2.send('包子 %s' %i)
producer()
我是[wupeiqi],我准备开始吃包子了
我是[yuanhao_SB],我准备开始吃包子了
wupeiqi 很开心的把【包子 0】吃掉了
yuanhao_SB 很开心的把【包子 0】吃掉了
wupeiqi 很开心的把【包子 1】吃掉了
yuanhao_SB 很开心的把【包子 1】吃掉了
.....
作业后边补