迭代器与生成器魔法,这俩就是一对老兄弟,为何说是老兄弟呢,在之前for循环遍历列表元组就是运用的迭代器的思想,函数就类似于生成器,只不过是return换成了yield,之前都出现过他们的表现形式,今天就来详细讲述一下。
对象必须提供一个next方法,执行该方法要么返回迭代的下一项,要么就引起stopteration异常,终止迭代(类似于for循环)
a = [1,2,3,'l','w'] a1 = a.__iter__() #使a成为迭代器 print(a1.__next__()) print(a1.__next__()) #每次next只读取一个数据 print(a1.__next__())
语法上和函数类似,自动实现迭代器协议,状态挂起
def product(): #生成器函数简答来说就是把普通函数中return转换为yield,__next__()控制运行 for i in range(100): print('正在生产包子') yield '一屉包子%s' %i #yield 遇到则停下(类似于return),再次调用函数则继续后边操作 print('正在卖包子') p = product() p.__next__() p.__next__()
①生成器的好处是延迟计算,一次返回一个结果,也就是说,他不会一次生成所有的结果,这就对于大数据的处理将会有用处。
②生成器还能有效提高代码的可读性。
①可以保留函数的运行状态,遇到yield就停下来,再次调用__next__()再接着运行。
②对于平常函数,是将数据全部存入列表,增加内存占空间,生成器函数反而减少了内存空间的使用。
[‘存储’ %i(赋予) (循环)取值]
a = ['爱你%s遍' %i for i in range(1,521)] print(a)
①列表解析的[]换成()就是生成器表达式。
②生成器表达式比列表解析更省内存。
import time #列表解析 start_time1 = time.time() a = sum([i for i in range(5200000)]) #占用内存大,机器容易卡死,耗时长 stop_time1 = time.time() #生成器表达式 start_time2 = time.time() b = sum(i for i in range(5200000)) #几乎不占内存,耗时短 stop_time2 = time.time() print('列表解析结果:',a,'所用时间:',(stop_time1-start_time1)) print('生成器表达式结果:',b,'所用时间:',(stop_time2-start_time2))
def get_polulation(): with open('人口普查','r',encoding='utf-8') as f: #简单的字典类型数据 for i in f: yield i g = get_polulation() s1 = eval(g.__next__()) #转化字典类型,迭代了一次 print(s1['population']) all_pop = sum(eval(i)['population'] for i in g) #因上面迭代了一次,此处就少迭代一次 print(all_pop) for p in g: #前面面迭代完成,从而再次将无法迭代,后面无法得出结果 print('%s %s' %eval(p)['population']/all_pop)
import time def consumer(name): print('我是%s,我准备开始吃包子了' %name) while True: baozi = yield time.sleep(1) print('%s 很开心的把%s吃掉了' %(name,baozi)) def producer(): c1 = consumer('L') #在生产者运转的同时消费者也在运行 c2 = consumer('W') c1.__next__() c2.__next__() for i in range(10): time.sleep(1) c1.send('包子%s' %i) c2.send('包子%s' % i) producer()
迭代器是循环遍历的内在,与列表解析比起来,生成器很大程度上减少了内存的使用,这两个应该在程序中起着重中之重的作用。