1、什么是生成器
通过列表生成式,我们可以直接创建一个列表,但是,这样创建的列表存在内存限制,代码如下:
a = [x for x in range(10)]
print(a)
结果是:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
那么当我的rang()的值是10万、100万。。。1亿啦,这样会创建列表,这样的列表会占用大量的内存,甚至导致内存溢出,程序挂掉等等问题,为了解决这样的问题,Python推出了生成器,即当我创建列表时,只是在内存中划分一块较小的空间用于存储列表生成式,而不生成列表,当需要使用列表中的值的时候才创建列表中的值,这就是生成器。
2、生成器的创建方式一
# 列表生成式
a = [x for x in range(10)]
print(a)
print("="*50)
# 生成器
b = (x for x in range(10))
print(b)
print(next(b))
print(next(b))
print(next(b))
print(next(b))
生成器的第一种创建方式是将生成式的[]变成()即可
生成器保存的是算法,每次调用next(b),就计算出b的下一个元素的值,直到计算到最后一个元素,如果没有更多元素时,抛出Stoplteration的异常。一般使用的是for循环来迭代生成器,并且不需要关心Stoplteration异常
3、生成器的创建方式二
如果列表值不是通过生成式生成的,而是通过一定的算法,通过第一次执行时生成的结果作为依据生成后续执行的结果,如斐波拉契数列,这样的可以通过生成器方式二创建,代码如下:
def createFib(num):
print("----start----")
a,b = 0,1
for i in range(num):
yield b
a,b = b,a+b
print("----end----")
return "end";
fib = createFib(5)
print(next(fib))
print(next(fib))
print(next(fib))
print(next(fib))
print(next(fib))
结果是:
----start----
1
1
2
3
5
(1)从结果可以看出,----end----没有打印,这是因为执行到yield b时进行了特殊的处理,程序停留在了yield b,当执行next时,才会继续向下执行,使用for则不会出现这种情况,代码如下:
for i in createFib(5):
print(i)
(2)next(fib)和fib.__next()__等价
(3)无法获取return的返回值,如果想要拿到返回值,必须捕获Stoplteration错误,返回值包含在Stoplteration的value中
while True:
try:
x = next(fib)
print("value:%d"%x)
except StopIteration as e :
print("生成器返回值:%s"%e.value)
break
4、生成器中的send
def fun():
i = 0
while i<5:
temp = yield i
print(temp)
i += 1
f = fun()
next(f)
next(f)
结果是:
0
None
1
当第一次执行next(f)时,运行到yield i,然后停止,等待下一次next,当第二次执行next(f)时,此时进行temp的赋值操作,但是现在没有进行值赋值给temp,所以输出的print(temp)为None,那么如何给temp赋值啦?可以通过send进行赋值操作,如下:
def fun():
i = 0
while i<5:
temp = yield i
print(temp)
i += 1
f = fun()
print(f.__next__())
print(f.send('为temp赋值成功'))
print(f.__next__())
5、多任务
def test1():
while True:
print("---1---")
yield None
def test2():
while True:
print("---2---")
yield None
t1 = test1()
t2 = test2()
while True:
t1.__next__()
t2.__next__()
这种多任务方式称为协程多任务,多任务分为协程、进程、线程