6.3. 生成器¶
6.3.1. yield语句¶
每次返回一个值,有点类似于return语句
冻结执行,程序每次执行到yield语句就会被暂停
return 语句一次返回所有数据,函数调用结束;而yield语句只返回一个元素数据,函数调用不会结束,只是 暂停,直到__next__()方法被调用,程序继续执行yield语句之后的语句代码。
6.3.2. 快速定义一个生成器¶
#!/usr/bin/env python
#-*- coding:utf8 -*-
a=(i for i in range(5))
print(a)
#生成器用法
print(type(a))
print(list(a))
代码示例1¶
#!/usr/bin/env python
#-*- coding:utf8 -*-
def myYield(n):
'''
定义一个生成器(03.函数)
'''
while n>0:
print("开始生成......")
yield n
print("完成一次......")
n -= 1
if __name__ == '__main__':
for i in myYield(4):
print("遍历得到的值:",i)
print()
my_yield = myYield(3) #生成一个生成对象
print("已经实例化生成器对象")
my_yield.__next__()
print("第二次调用__next__()方法:")
my_yield.__next__()
代码示例2¶
#!/usr/bin/env python
#-*- coding:utf8 -*-
def myYield(n):
'''
:return:rcv用来接收调用者传来的值
'''
while n >0:
rcv = yield n #rcv用来接收调用者传来的值
n -=1
if rcv is not None:
n = rcv
if __name__ == '__main__':
my_yield = myYield(3)
print(my_yield.__next__())
print(my_yield.__next__())
print("传给生成器一个值,重新初始化生成器")
print(my_yield.send(10))
print(my_yield.__next__())
代码示例3¶
#!/usr/bin/env python
#-*- coding:utf8 -*-
#通过生成器推导式构建
def generator():
print(123)
content = yield 1
print("===========",content)
print(456)
yield 2
g = generator()
ret = g.__next__()
print("*****",ret)
ret = g.send("hello")
print("****",ret)
print()
def func1():
print(11)
print(333)
yield 222
print(666)
yield 777
g_obj = func1()
print(g_obj.__next__())
print(g_obj.__next__())
eg
#!/usr/bin/env python
# -*- coding:utf8 -*-
# auther; 18793
# Date:2019/5/17 23:21
# filename: 生成器test.py
def square(num):
for i in range(1, num + 1):
yield i * i
# for i in square(5):
# print(i, end=" ")
hujianli = square(5)
print(hujianli.__next__())
print(hujianli.__next__())
print(hujianli.__next__())
print(hujianli.__next__())
print(hujianli.__next__())
print(hujianli.__next__())
生成器函数通过yield返回数据,与return不同的是,
return语句一次返回所有数据,函数调用结束;
而yield语句只返回一个元素数据,函数调用不会结束,只是暂停,
直到__next__()方法被调用,程序继续执行yield语句之后的语句代码
生成器函数同样实现了与普通函数同样的功能,它们有如下区别:
1.生成器代码更简洁。(代码少,结构更为简洁)
2.生成器内存占用极少。(与普通函数相比,普通函数面临严重的内存问题)
3.运行方式不同。(普通函数是顺序执行的,直到遇到return语句就返回,而生成器函数则是遇到yield语句返回,再次执行时,从上次离开的地方继续执行。)
6.3.3. 生成器和协程¶
示例¶
#!/usr/bin/env python
# -*- coding:utf8 -*-
import time
cake = "🍰"
# 一个简单的生产者与消费者编程模型
def consumer():
print("等待接收处理任务.......")
while True:
data = (yield)
print("收到 {0},开始品尝 【{1}】:".format(data, cake))
time.sleep(0.5)
print("蛋糕被吃完了........哈哈哈哈哈嗝")
print()
def producer():
c = consumer()
c.__next__()
print("模拟生产者模型")
for i in range(1, 5):
time.sleep(1)
print("开始制作第{0}个蛋糕, 【{1}】【{2}】做好了.....".format(i, cake, i))
c.send("蛋糕:【%s】" % i)
if __name__ == '__main__':
producer()
输出信息:
等待接收处理任务.......
模拟生产者模型
开始制作第1个蛋糕, 【🍰】【1】做好了.....
收到 蛋糕:【1】,开始品尝 【🍰】:
蛋糕被吃完了........哈哈哈哈哈嗝
开始制作第2个蛋糕, 【🍰】【2】做好了.....
收到 蛋糕:【2】,开始品尝 【🍰】:
蛋糕被吃完了........哈哈哈哈哈嗝
开始制作第3个蛋糕, 【🍰】【3】做好了.....
收到 蛋糕:【3】,开始品尝 【🍰】:
蛋糕被吃完了........哈哈哈哈哈嗝
开始制作第4个蛋糕, 【🍰】【4】做好了.....
收到 蛋糕:【4】,开始品尝 【🍰】:
蛋糕被吃完了........哈哈哈哈哈嗝
6.3.4. 尽量使用生成器代替列表¶
##不推荐
def my_range(n):
i = 0
result = []
while i < n:
result.append(fn(i))
i += 1
return result # 返回列表
##推荐
def my_range(n):
i = 0
result = []
while i < n:
yield fn(i) # 使用生成器代替列表
i += 1
*尽量用生成器代替列表,除非必须用到列表特有的函数。