生成器generator
2019-07-25 23:00 风e逸 阅读(162) 评论(0) 收藏 举报生成器:
通过列表生成式,我们可以直接创建一个列表,但是,受到内存限制,列表容量肯定是有限的,而且创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间,在Python中,这种一边循环一边计算的机制,称为生成器:generator
生成器是一个特殊的程序,可以被用作控制循环的迭代行为,python中生成器是迭代器的一种,使用yield返回值函数,每次调用yield会暂停,而可以使用next()函数和send()函数恢复生成器。
生成器类似于返回值为数组的一个函数,这个函数可以接受参数,可以被调用,但是,不同于一般的函数会一次性返回包括了所有数值的数组,生成器一次只能产生一个值,这样消耗的内存数量将大大减小,而且允许调用函数可以很快的处理前几个返回值,因此生成器看起来像是一个函数,但是表现得却像是迭代器。
为什么用生成器:
1.生成器可以一边计算,一边循环,因此可以省去列表的储存空间。归根结底,为了节省储存空间。
2.生成器可以暂停函数返回值,因此可以生成一个值,然后对这个值进行操作,然后在继续生成值,继续操作。比较便利。生成器的定义:
第一种方法,与定义列表相似,只是将[ ],改为 ( )。
1 # 生成列表: 2 list1 = [x for x in range(5)] 3 print(list1) 4 # 生成器: 5 ge_list1 = (x for x in range(5)) 6 print(next(ge_list1)) 7 print(next(ge_list1)) 8 print(next(ge_list1)) 9 # 直接print(ge_list1) 返回结果是一个生成器<generator object <genexpr> at 0x00000000025C4660>
第二种方法,def(): yeild
1 import time 2 def scq(): 3 4 print('---准备生孩子---') 5 print('---准备生孩子---') 6 yield '我' 7 time.sleep(3) 8 print('---准备生孩子---') 9 yield '儿子' 10 time.sleep(3) 11 print('---准备生孩子---') 12 yield '孙子' 13 req = scq() 14 print(req.__next__()) 15 print(req.__next__()) 16 print(req.__next__())
生成器的复杂处理:
1 # 新建一个文件,名字叫 人口普查 2 # 内容为: 3 # {'name': '北京', 'popu': 10} 4 # {'name': '黑龙江', 'popu': 100000000} 5 # {'name': '南京', 'popu': 111111111111} 6 7 8 def get_po(): 9 with open('人口普查','r',encoding='utf-8') as f: # 文件操作 10 for i in f: 11 yield i 12 13 g = get_po() 14 s1 = eval(g.__next__()) # 执行起来的生成器返回值并不是字典形式,只是输出显示像是字典,要想变成字典进行关键字取值,需要用eval()转换 15 # print(s1['popu']) 16 # print(s1['name']) # 字典取值时,因为s1保存了运行第一次的值,因此s1其实内容就是字典{'name': '北京', 'popu': 10},因此本次取值返回结果为:北京 17 # print(g.__next__()) 本次取值是从第二条开始,因为s1中已经next过一次。 18 s2 = eval(g.__next__()) # 接下来可以正常取s2中的值 19 # 求总人口数 20 all_popu = sum(eval(i)['popu'] for i in g) # 先取出i的值,然后对i的值进行处理 21 print(all_popu)
生成器的另一个运行命令: send(value)
send(value),表示将value值返回给yield,并有yield赋值给接收的变量
1 def test(): 2 print('开始制作') 3 f = yield 1 4 print('第一次', f) 5 s=yield 2 6 print('第二次',s) 7 8 res = test() 9 print(res.__next__()) 10 print(res.send(5)) 11 12 输出结果: 13 开始制作 14 1 15 第一次 5 16 2 17 18 # 需要注意的是,由于send()输入的值由第一次的yield传递给f,因此在第二次运行时才能触发,因此,send()一般前面会先运行一次生成器。若send()为首次运行生成器,则value值需为None,此时的send()功能与__next__()相同
浙公网安备 33010602011771号