一.什么是生成器
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了
1.while的列表推导
list.append(i)
2.for的列表推导,range与切片很类似
for i in range(10,78):
3.第一个i是元素的值,后面的for是循环的次数,如果第一个i=11,那么所有的元素都是11
a=[i for i in range(1,18)]
4.for控制循环的次数,for和if的嵌套
c = [i for i in range(10) if i%2==0]
5.每执行第一个for循环都要执行第二个for循环的所有次数
d = [i for i in range(3) for j in range(2)]
6.每执行第一个for循环都要执行第二个for循环的所有次数
d = [(i,j) for i in range(3) for j in range(2)]
二.创建生成器方法1
要创建一个生成器,有很多种方法。第一种方法很简单,只要把一个列表生成式的[ ]改成( )
如:L = [ x*2 for x in range(5)]
和G = ( x*2 for x in range(5))
,L是一个列表,而G是一个生成器,可以通过next(G)函数获得生成器的下一个返回值,不断调用 next()实在是太变态了,正确的方法是使用for循环,因为生成器也是可迭代对象
三.创建生成器方法2
fib函数变成generator,只需要把print(b)改为yield b就可以了,循环过程中不断调用yield ,就会不断中断。当然要给循环设置一个条件来退出循环,不然就会产生一个无限数列出来,当循环到没有元素的时候,将会生成异常,这时候就要用try和exception来检测异常,#print自动检测异常并停止,但是next()就要用try ,在创建生成器的时候需要接收函数的返回值
#1.next(返回函数名)
#2.返回函数名.__next__()是一样的方法来获取下一个返回值
总结:生成器是这样一个函数,它记住上一次返回时在函数体中的位置。对生成器函数的第二次或第 n 次调用跳转至该函数中间,而上次调用的所有局部变量都保持不变,生成器不仅记住了它数据状态;生成器还记住了它在流控制构造(在命令式编程中,这种构造不只是数据值)中的位置
四.生成器的特点
1.节约内存
2.迭代到下一次的调用时,所使用的参数都是第一次所保留下的,即是说,在整个所有函数调用的参数都是第一次所调用时保留的,而不是新创建的
五.send用法
1.如果在在程序中有个变量等于yield,不是说把yield的值给了这个变量,而是接下来在下一次调用执行一次的时候可以传一个值,t.send("haha")
和t.__next__()
都可以让生成器继续执行,不同的是send可以传递一个值,但是不能在程序刚开始执行就用send传值,有两种方法,要么先用__next__
调用一次,再send一个值,或者t.send(None)
2.生成器:完成多任务,控制多个任务执行的情况