迭代器
须知:迭代是一个重复的过程,且每次重复都是基于上一次的结果而来。
eg1:这只是单纯的重复,且每次结果都一样
while True: print('123')
eg2:这是一次重复过程,且每次都是基于上一次得到结果
l=['a','b','c'] n=0 while n<len(l): print(l[n]) n+=1
目的:能够迭代取值!!
1、迭代器:迭代取值的工具
2、可迭代对象:
在python中,但凡内置有__iter__方法的对象,都是可迭代对象(比如:str list tuple dict set file)
以下都是可迭代对象:str1="hello" list1=['a','b','c'] tup1=(1,2,3) dic={'x':1,'y':2} s1={'a','b','c'} f=open('a.txt','w',encoding='utf-8')
特点:内置有__iter__方法的都可以是可迭代对象,执行完该方法得到一个迭代器对象。
3、迭代器对象:
注:file(文件)既有__iter__,也有__next__方法,则文件本身就是迭代器对象。
3-1)获取方式:执行可迭代对象的__iter__方法,拿到的返回值就是迭代器对象。
3-2)特点:内置有__next__方法,执行该方法能得到值;
内置有__iter__方法,执行该方法拿到迭代器本身。
l='psy' #l为可迭代对象
iter_l=l.__iter__() #iter_l为迭代器对象
while True:
try:
res=iter_l.__next__()
print(res)
except StopIteration:
break
分析2和3:
可迭代对象:内置有__iter__方法 迭代器对象:内置有__iter__和__next__方法
可迭代对象不一定是迭代器对象 迭代器对象一定是可迭代对象。
4、迭代器的优点
4-1)提供了一种可不依赖索引的取值方法====》利用迭代器对象的__next__方法
但是此方法较为麻烦:(1)要先把可迭代对象变成迭代器对象(__iter__方法)
(2)使用迭代器对象的__next__方法,会报错(使用try: except;避免)
So引入for循环====》迭代器循环 【in后面必须要是可迭代对象】
l='psy' #l为可迭代对象 for item in l: print(item)
4-2)迭代器更省空间
5、迭代器的缺点
取值麻烦,只能一个一个的取值,从前往后,不能回头
生成器 利用yield关键字
不恰当的例子:函数就像母鸡生鸡蛋
before:原先母鸡生鸡蛋:
def chicken(): print('===>first') return 1 print('===>second') return 2 print('===>third') return 3 res=chicken() print(res)
注:此时遇到return 就返回,所以最终只能生一个鸡蛋
now:利用生成器(yield),母鸡生鸡蛋:
def chicken():
print('===>first')
yield 1
print('===>second')
yield 2
print('===>third')
yield 3
obj=chicken()
print(obj) #<generator object chicken at 0x000001E00ED92C50>
注:此时的obj是一个生成器,但是obj下面有__iter__和__next__方法,所以obj也是迭代器对象【利用for循环,可以得到里面的值】
1、生成器:
(1)函数内包含yield关键字;
(2)再调用函数,就不会执行函数体代码,拿到的返回值是一个生成器对象。
2、实质
生成器本质就是迭代器【===》咋用迭代器,就咋用生成器】
针对上面的obj(obj=chicken(),此时obj是一个生成器,也是一个迭代器,利用for循环得到结果)
for item in obj:
print(item)
这两行代码的实际流程:(1)iter_obj=obj.__iter__() 拿到迭代器;
(2)出发iter_obj.__next__() 拿到该方法的返回值,赋值给item;
(3)周而复始,直到函数内不再有yield,则取值完毕;
(4)for 会自动检测到StopIteration异常,结束循环。
3、yield理解
(1)提供了一种自定义迭代器的方法
【可以在函数内使用yield关键字,调用函数拿到的结果就是一个生成器,生成器就是迭代器】
(2)yield可以像return一样用于返回值,区别:return只能返回一次值,yield能够返回多次值!
【因为yield可以保存函数执行的状态】
4、yield进阶 【一个小例子(小猪吃东西)】
4-1)简单版
def eat(name): print('{} is ready to eat'.format(name)) while True: food=yield #一开始的时候,food为None,因为没有传值 print('eat {}'.format(food)) pig=eat('胖猪') print(pig) #<generator object eat at 0x0000026BFF3CF678> #1、必须初始化,让函数停在yield位置 pig.__next__() #胖猪 is ready to eat #2、接下来就是喂猪,利用send """ send有两个功能:(1)给yield传值。(2)同__next__功能 """ pig.send('泔水') #eat 泔水 pig.send('猪粮') #eat 猪粮
4-2)较难版 【自己多琢磨琢磨吧。。。。。。】
def eat(name):
print('{} is ready to eat'.format(name))
food_list=[]
while True:
food=yield food_list
food_list.append(food)
print('eat {}'.format(food_list))
pig=eat('瘦猪')
print(pig) #<generator object eat at 0x000001F62EBBF678>
#1、必须初始化,让函数停在yield位置
res=pig.__next__()
print(res)
"""
瘦猪 is ready to eat
[]
"""
res1=pig.send('泔水')
print(res1)
"""
eat ['泔水']
['泔水']
"""
print('***')
res2=pig.send('猪粮')
print(res2)
"""
eat ['泔水', '猪粮']
['泔水', '猪粮']
"""
迭代器和生成器的总结
1、迭代器:
可迭代对象:只有__iter__方法 可迭代对象通过__iter__方法,得到迭代器对象
迭代器对象:有__iter__和__next__方法 迭代器对象通过__iter__方法得到它本身,迭代器对象通过__next__方法得到值
for循环就是迭代循环,能被for循环的,一定是可迭代对象。
2、生成器
在函数内部加上yield关键字,得到一个生成器!
补充:列表生成式与生成器表达式
1、列表生成式【便捷】 ====>针对数据量比较小
eg:生成一个列表,为['egg0','egg1','egg2',......'egg100']
before:
eggs=[] for i in range(101): eggs.append('egg{}'.format(i))
now:利用列表生成式
eggs=['egg{}'.format(i) for i in range(101)]
还可以加上判断:
eggs=['egg{}'.format(i) for i in range(101) if i>10]
列表生成式的语法:[expression for item in iteration if condition] 《=等价=》 [表达式 for循环 if判断]
但是:列表生成式占内存空间,所以引入:生成器表达式
2、生成器表达式 ====>针对数据量比较大
针对上题:
eggs=('egg{}'.format(i) for i in range(101)) print(eggs) #<generator object <genexpr> at 0x000002399DFBF678> #发现eggs具有__iter__和__next__ 所以生成器本身就是迭代器 #此时可通过以下方法取值 print(eggs.__next__()) #egg0 print(next(eggs)) #egg1
生成器表达式的语法:(expression for item in iteration if condition) 《=等价=》 (表达式 for循环 if判断)
3、练习题
(1)将names=['psy','xk','dd']中的字符变成大写
names=['psy','xk','dd'] res=[name.upper() for name in names] print(res) #['PSY', 'XK', 'DD']
(2)将names=['psy','xk','dd_good']中以good结尾的名字过滤,然后保存剩下的长度
names=['psy','xk','dd_good'] res=[len(name) for name in names if not name.endswith('good')] print(res) #[3, 2]