一、迭代器
迭代器的概念
#迭代器即迭代的工具,那什么是迭代呢? #迭代是一个重复的过程,每次重复即一次迭代,并且每次迭代的结果都是下一次迭代的初始值
迭代器协议和for循环工作机制
#for循环的工作原理 #1:执行in后对象的dic.__iter__()方法,得到一个迭代器对象iter_dic #2: 执行next(iter_dic),将得到的值赋值给k,然后执行循环体代码 #3: 重复过程2,直到捕捉到异常StopIteration,结束循环
# l = [1,2,3,4,5,6,7,8,9]
#
# iter_l = l.__iter__()
#
# print(iter_l.__next__())
# print(iter_l.__next__())
# print(next(iter_l)) #next本质就是调用__next__
迭代器的优缺点
#优点: - 提供一种统一的、不依赖于索引的迭代方式 - 惰性计算,节省内存 #缺点: - 无法获取长度(只有在next完毕才知道到底有几个值) - 一次性的,只能往后走,不能往前退
二、生成器
什么是生成器
#只要函数内部包含有yield关键字,那么函数名()的到的结果就是生成器,当调用函数并且不会执行函数内部代码,只有得到__next__指令时才会往下执行
def func():
print('====>first')
yield 1
print('====>second')
yield 2
print('====>third')
yield 3
print('====>end')
g=func()
print(g) #<generator object func at 0x0000000002184360>
1、生成器函数
#1、生成器函数
def test():
yield 1
yield 2
g = test()
print(g.__next__())
print(g.__next__())
print(next(g))
def product_baozi():
ret = []
for i in range(10):
ret.append('鸡蛋%s' %i)
return ret
#缺点1:占空间大
#缺点2:效率低,因为要全部蛋下完才可以
def product_baozi():
for i in range(100):
print('正在生产包子')
yield '一屉包子%s' %i
print('开始卖包子')
pro_g = product_baozi()
baozi1 = pro_g.__next__()
baozi1 = pro_g.__next__()
print(baozi1)
#也可以这么写
baozi = product_baozi()
for i in baozi:
print(i)
返回值是yield 可以多个yield,yield相当于return,yield可以保持函数的运行状态
2、生成式表达式
#2、生成式表达式
lmj = ('鸡蛋%s' %i for i in range(10)) #生成器表达式
print(lmj.__next__())
print(next(lmj))
n = sum(i for i in range(10000))
print(n)
sum(list(range(1000000000)))
生成器就是迭代器
g.__iter__ g.__next__ #2、所以生成器就是迭代器,因此可以这么取值 res=next(g) print(res)
生成器表达式之后就有一个__next__方法
三元表达式
name = 'aln' res = 'sb' if name == 'alb' else '帅哥' print(res)
列表解析
egg_list = [] for i in range(10): egg_list.append('鸡蛋%s' %i) print(egg_list) #这种方法更快速 l = ['鸡蛋%s' %i for i in range(10)] #列表解析 l1 = ['鸡蛋%s' %i for i in range(10) if i>5] # l1 = ['鸡蛋%s' %i for i in range(10) if i>5 else i] #没有四元表达式 print(l) prinzt(l1)
总结:
# 1、把列表解析的[]换成()得到的就是生成器表达式
# 2、列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存
注意:
#列表解析
sum[i for in range(100000000000000)] # 内存占用大,机器容易卡死
#生成器表达式
sum(i for i in range(100000000000000))# 几乎不占用内存
例子
获取每个省占用全国人口的百分比(通过获取文件的每一行)
#获取每个省占用全国人口的百分比
"""人口文件的内容
{'name':'山东','population':10}
{'name':'山西','population':888}
{'name':'河南','population':765}
{'name':'河北','population':6546}
{'name':'广西','population':353}
"""
def get_population_count():
with open('人口普查', 'r',encoding='utf-8') as f:
for i in f: # 每次循环一次,取出来的是一行的内容
yield i
g = get_population_count()
#g.__next__()生成的是字符串,需要通过使用eval函数将字符串转换成字典模式
s1 = eval(g.__next__())
print(g.__next__())
print(type(s1))
print(s1['population'])
# #方法一、获取总人口
# total_population = 0
# for i in g:
# p_dic = eval(i) #通过eval将字符串获取成字典形式
# print(p_dic['population'])
# total_population += eval(i)['population']
# print('总人口%s' %total_population)
#方法二、获取总人口
all_population = sum(eval(i)['population'] for i in g)
print('总人口%s' %all_population)
注意:迭代只迭代一次,上面方法一用了迭代,再用方法二就会得到迭代的值
g.__next__()生成的是字符串,需要通过使用eval函数将字符串转换成字典模式
s1 = eval(g.__next__())
并发编程,一边吃包子,一边生成,通过send函数,然后通过yield来接收
yield 相当于return控制的是函数的返回值
x= yield的另一个特性,接收send传过来的值,赋值给x
def test():
print('开始啦')
first = yield 1 #first = None
print('第一次',first)
sec = yield 2
print('第二次',sec)
yield
t = test()
print(t.__next__())
t.send(None)
t.send('传给停留yield的那个位置的yield')
#*****************************************************************************************************************************************************************************************************************************************************************************
import time
def consumer(name):
print('我是[%s], 我准备开始吃包子'%(name))
while True:
baozi = yield
time.sleep(1)
print('%s 很开心把[%s]吃掉了'%(name,baozi))
def producer():
c1 = consumer('1号选手')
c2 = consumer('1号选手')
c1.__next__()
c2.__next__()
for i in range(10):
time.sleep(1)
c1.send('肉馅 %s' %i)
c2.send('肉馅 %s '%i)
producer()
注意:yield 相当于return控制的是函数的返回值
x= yield的另一个特性,接收send传过来的值,赋值给x