迭代器
1 什么叫迭代:迭代是一个重复过程,每次重复都是基于上一次的结果来的
2 为什么要用迭代器?
l=['a','b','c']
n=0
while n < len(l):
print(l[n])
n+=1
- 对于序列类型:字符串,列表,元组,可以使用基于索引的迭代取值方式,而对于没有索引的类型,如字典,
集合、文件,这种方式不再适用,于是我们必须找出一种能不依赖于索引的取值方式,这就是迭代器
3 可迭代的对象:只要对象内置有__iter__方法,obj.__iter__
数字不可迭代
4 迭代器对象:对象既内置有__iter__方法,又内置有__next__,如文件对象
注意:可迭代对象不一定是迭代器对象,而迭代器对象一定是可迭代的对象
# 可迭代的对象
# 'hello'.__iter__ 字符串
# [1,2].__iter__ 列表
# (1,2).__iter__ 元组
# {'a':1}.__iter__ 字典
# {1,2,3}.__iter__ 集合
1 dic={'a':1,'b':2,'c':3} 2 iter_dic=dic.__iter__() 3 print(dic.__iter__() is dic) 4 False 5 6 print(iter_dic.__iter__() is iter_dic) 7 True
可迭代对象执行__inter__方法之后会得到迭代器对象 (迭代器对象有__next__方法)
可迭代对象 不等于自己的__inter__()
迭代器对象等于自己
可迭代对象 和迭代器对象 __inter__() 之后都会得到迭代器
for循环的本质
1 # while True: 2 # try: 3 # i=next(iter_dic) 4 # print(i) 5 # except StopIteration: 6 # break 7 # 8 9 # for i in dic: #iter_dic=dic.__iter__() 10 # print(i)
迭代器的优缺点:
- 优点:
提供了一种统一的迭代取值方式,该方式不再依赖于索引
更节省内存
同一时间内存只有一个值(T级别的文件打开,然后一个next读一个,内存中就一个值)
- 缺点:
无法统计长度
一次性的,只能往后走,不能往前退,无法获取指定位置的值
生成器---关键字 yield
定义:只要函数内部出现yield关键字,那么再调用该函数,将不会立即执行函数体代码,会到到一个结果
该结果就是生成器对象
生成器本质就是迭代器
yield 可以制作自己的迭代器
yield的功能:
- 为我们提供了一种自定义迭代器的方式
- 对比return,可以返回多次值,挂起函数的运行状态
1 # 自定义功能,可以生成无穷多个值,因为同一时间在内存中只有一个值 2 def my_range(start,stop,step=1): 3 while start < stop: 4 yield start 5 start+=step 6 7 8 # g=my_range(1,5,2) #1 3 9 print(next(g)) 10 print(next(g)) 11 print(next(g)) 12 print(next(g)) 13 print(next(g)) 14 15 for i in my_range(1,1000000000,step=2): 16 print(i)
1 def func(): 2 print('===>first') 3 yield 1 4 print('===>second') 5 yield 2 6 print('====>third') 7 yield 3 8 9 10 g=func() 11 print(g) 12 13 生成器本质就是迭代器 14 print(next(g)) 15 print(next(g)) 16 print(next(func())) 17 print(next(func())) 18 19 20 for i in g: 21 print(i)
for循环的本质就是做了while i=next(g)的操作。而yield又将后面的值 返回给了next(g) 如果不打印i(pirnt(i)) 得到的就会是:
print('===>first')
print('===>second')
print('====>third')
而没有yield的返回值
yield的表达式形式的应用 def eater(name): food_list=[] print('%s 开动啦' %name) while True: food=yield food_list #food=‘骨头’ print('%s 开始吃 %s' %(name,food)) food_list.append(food) g=eater('大壮') g.send(None) #next(g) print(g.send('骨头')) print(g.send('牛肉'))
#对于表达式形式的yield,在使用时,第一次必须传None,g.send(None)等同于next(g)
g.send(None) 执行代码 遇见第一个yeild 停留 return第一个yeild 后面的值
send('骨头')的操作实际上是会涉及两个yeild,
- 1 先将'骨头'赋值给上一个执行next(g)操作停留的yield 于是有了food=yeild=‘骨头’ 这个yeild是执行next(g)后停留yeild_1.
- 2 然后再进行next(g)的操作(------------就是向下执行代码)。
- 3 到下一个yield_2后,将yield_2面的值 返回给next(g), 也就是 next(g)(或者说是g.send(骨头))现在已经是['骨头'].
作用 可以给函数传入多次值。
g.close()可以关闭传值