需要明确,生成器是迭代器,具备可迭代功能,但是反之不成立。
1 创建生成器
1.1 列表生成式
可以用[ ] 里面加入表达式和函数的形式生成一个列表
a = [x for x in range(9)]
print(type(a))
a = [x*x for x in range(9)]
print(a)
def f(n):
return n*n*n
print([f(x) for x in range(8)])
1.2 用小括号()生成生成器
生成器比传统的列表节省省空间,是一种用的时候才会产生占用内存数据的懒工厂方式
'''生成器小括号产生方式'''
a = (x for x in range(9))
print(type(a))
a = (x*x for x in range(9))
for i in a:
print(i, end='\t')
print()
def f(n):
return n*n*n
a= (f(x) for x in range(8))
for i in a:
print(i, end='\t')
1.3 yield创建生成器函数
yiel是一个语法糖,替换return语句之后实现返回功能,内部实现迭代器协议,同时保持状态可以挂起。
'''菲波纳契数列--生成器版'''
def fibonacci(max):
n, a, b = 0, 0, 1
while n <= max:
a, b = b, a+b
yield b
n += 1
for k in fibonacci(5):
print(k, end='\t')
代码解释,k在执行for语句得时候相当于每一次取到next()迭代后的值,而每一次都是直行道yield返回的值即为迭代后的值,相当于执行以下代码:
'''菲波纳契数列--生成器版'''
def fibonacci(max):
n, a, b = 0, 0, 1
while n <= max:
a, b = b, a+b
yield b
n += 1
f = fibonacci(5)
k = next(f)
print(k)
k = next(f)
print(k)
k = next(f)
print(k)
k = next(f)
print(k)
k = next(f)
print(k)
k = next(f)
print(k)
k = next(f)
print(k)
StopIteration:在函数执行结束(正常结束,或者遇到return)之后,没有遇到yield就会抛出该错误。相当于某一次next()方法没有遇到yield执行完函数即抛出该错误。
另外,遇到了StopIteration错误之后for进行自动处理了。
1.4 理解两次调用生成器函数
'''理解两次调用生成器函数产生的效果:相当于两个对象,用类的思想很好理解'''
def fibonacci(max):
n, a, b = 0, 0, 1
while n <= max:
a, b = b, a+b
yield b
n += 1
f = fibonacci(5)
f2 = fibonacci(4)
for k in f:
print('f1:', k, end='\t')
for j in f2:
print('f2:', j, end='\t')
2 .send() 方法理解和应用
当调用send的时候将执行两个步骤:
- 传参给yield语句(整体)
- next()
因为第一次调用没有遇到yield,因此第一次send(None),否则会报错
'''初级测试send()'''
def foo(n):
print('运行开始')
while n > 0:
count = (yield 7) * n
print(count, n)
n -= 1
return 1
f = foo(3)
f.send(None)
f.send(9)
f.send(12)
f.send(22)
f.send(32)
3 生成器函数实现协程应用
所谓协同程序也就是是可以挂起,恢复,有多个进入点。其实说白了,也就是说多个函数可以同时进行,可以相互之间发送消息等。
#基于yield实现异步
import time
def consumer():
'''任务1:接收数据,处理数据'''
while True:
x=yield
# print(x, end='\t')
time.sleep(0.2)
print(x)
def producer():
'''任务2:生产数据'''
g=consumer()
next(g)
for i in range(100):
g.send(i)
producer()