# 迭代器
# 迭代器是一个重复的过程,每次取值都是基于上一次的结果,而进行迭代取值的工具
#
# 拥有:
# __iterator__ 和 __next__内置方法
# 注意:
# 1.重复取值,单纯的重复取值的不是迭代器对象
# 2.每次取值都是基于上次取值结果而进行
#
# 作用:
# 提供了一种不依赖于索引的迭代取值的方式
#
# 分类:
# 可迭代的对象:list tuple dict set
# 迭代器对象:file 生成器 内置有iter next方法
# 实例:
# l=[1,2,3,4,5,6]
# iter_l=l.__iter__()#调用可迭代的对象__iter__得到一个新的迭代器对象
# print(iter_l.__next__())#迭代1次
# print(iter_l.__next__())#迭代2次
# print(iter_l.__next__())#迭代3次
# 按照next的次数依次的输出结果,有几个next就输出几次结果
#是依据上次的迭代结果一次进行next结果输出
#因为只产生了依次iter_l=l.__iter__(),下面的next的输出都是按照这个迭代对象
# 依次的输出
# 错误方式:
# print(l.__iter__().__next__())#迭代1次
# print(l.__iter__().__next__())#迭代2次
# print(l.__iter__().__next__())#迭代3次
# 输出结果:
# 1
# 1
# 1
# 因为进行迭代时,每次都是l列表产生新的迭代器的对象,都是重新进行next,是一个单纯的重复的过程
# 注:之所以可迭代对象和迭代器对象都有iter,和next的方法,是为了进行统一,迭代机制统一。
#
# 总结:
# 优点:
# 1.提供一种不依赖索引的取值方式
# 2.同一时刻内存中只存在一个值,而且只能往后去
# 缺点:
# 1.取值不能按照索引取值,只能往后一个个的取
# 2.无法预测迭代器的长度,因为迭代器是一个个的网下取值,知道报错,才停止。
迭代器
迭代是一个重复的过程,并且每次重复都是基于上一次的结果而来 #仅仅循环,不是迭代
可迭代对象:在python中,但凡内置有__iter__方法的对象,都是可迭代的对象
以下都是可迭代的对象
str1='hello'
list1=[1,2,3]
tup1=(1,2,3)
dic={'x':1}
s1={'a','b','c'}
f=open('a.txt','w',encoding='utf-8')
迭代器:迭代取值工具,可迭代的对象执行__iter__方法得到的返回值就是迭代器对象
dic={'x':1,'y':2,'z':3}
iter_dic=dic.__iter__()
print(iter_dic.__next__())
print(iter_dic.__next__())
print(iter_dic.__next__())
print(iter_dic.__next__())
可迭代的对象vs迭代器对象
可迭代的对象:str,list,tuple,dict,set,file(文件本身就是迭代器)
a、获取可迭代对象的方式:无须获取,python内置str,list,tuple,dict,set,file都是可迭代对象
b、特点:
内置有__iter__方法的都叫可迭代的对象,执行该方法会拿到一个迭代器对象
迭代器对象:文件对象本身就是迭代器对象 #迭代器对象一定是可迭代对象
a、获取迭代器对象的方式:
执行可迭代对象的__iter__方法,拿到的返回值就是迭代器对象
b、特点:
内置有__next__方法,执行该方法会拿到迭代器对象中的一个值
内置有__iter__方法,执行该方法会拿到迭代器本身
iter_x=x.__iter__()
iter_x.__next__()
print(iter_x.__iter__().__iter__().__iter__().__iter__() is iter_x) #拿到的还是本身
迭代器的优缺点分析
迭代器提供了一种可不依赖于索引的取值方式(优点)
#字典无序,没有办法通过索引取值,可通过迭代器取值
l=open('a.txt','r',encoding='utf-8')
iter_l=l.__iter__()
while True:
try:
print(iter_l.__next__())
except StopIteration:
break
迭代器更加节省内存(优点)#迭代器本身是一个内存地址
#range在python2中是一个列表,在python3中是一个迭代器
取值麻烦,只能一个一个取,只能往后取(缺点)
并且是一次性的,无法用len获取长度(缺点)
for循环原理分析
a、for 循环称之为迭代器循环,in后跟的必须是可迭代的对象 #while 循环称为条件循环
b、for循环会执行in后对象的__iter__方法,拿到迭代器对象
c、然后调用迭代器对象的__next__方法,拿到一个返回值赋值给line,执行一次循环体
d、周而复始,直到取值完毕,for循环会检测到异常自动结束循环
for line in l: #iter_l=l.__iter__()
print(line)
for item in {'x':1,'y':2}:
print(item)
生成器:函数内包含有yield关键字,再调用函数,就不会执行函数体代码,拿到的返回值就是一个生成器对象
def chicken():
print('=====>first')
yield 1
print('=====>sencond')
yield 2
print('=====>third')
yield 3
obj=chicken()
res=obj.__next__()
print(res)
res1=obj.__next__()
print(res1)
res2=obj.__next__()
print(res2)
1、iter_obj=obj.__iter__(),拿到迭代器
2、触发iter_obj.__next__(),拿到该方法的返回值,赋值给item
3、周而复始,直到函数内不在有yield,即取值完毕
4、for会检测到StopIteration异常,结束循环
for item in obj:
print(item)
总结yield:
1、为我们提供了一种自定义迭代器的方式,可以在函数内用yield关键字,调用函数拿到的结果就是一个生成器,生成器就是迭代器
2、yield可以像return一样用于返回值,区别是return只能返回一次值,而yield可返回多次。因为yield可以保存函数执行的状态
def my_range():
print('start........')
n=0
while True:
yield n
n+=1
obj=my_range()
print(obj)
print(obj.__next__())
print(obj.__next__())
print(obj.__next__())
print(obj.__next__())
for i in my_range():
print(i)
def my_range(start,stop,step=1):
n=start
while n < stop:
yield n #yield 4
n+=step #5
obj=my_range(3,7,2) #3,5,
print(obj.__next__())
print(obj.__next__())
print(obj.__next__())
print(obj.__next__())
print(obj.__next__())
for item in my_range(5,10,2):
print(item)
生成器之yield的表达式形式
def eat(name):
print('%s ready to eat' %name)
food_list=[]
while True:
food=yield food_list # food='骨头'
food_list.append(food) #food_list=['泔水','骨头']
print('%s start to eat %s' %(name,food))
dog1=eat('alex')
1、必须初始化一次,让函数停在yield的位置
res0=dog1.__next__()
print(res0)
2、接下来的事,就是喂狗
send有两方面的功能
a、给yield传值
b、同__next__的功能
res1=dog1.send('泔水')
print(res1)
res2=dog1.send('骨头')
print(res2)
res3=dog1.send('shit')
print(res3)