迭代器
迭代器指的是迭代取值的工具,迭代是一个重复的过程,每次重复都是基于上一次的结果而继续的,单纯的重复并不是迭代。
可迭代对象:内置有__iter__
方法的都称之为可迭代的对象。
字符串、列表、元组、字典、集合和读写的文件对象都有__iter__
方法;
str1 = 'hello'
str1.__iter__()
l1 = [1, 2, 3, 4]
l1.__iter__()
t1 = (1, 2, 3)
t1.__iter__()
d1 = {'a': 1, 'b': 2}
d1.__iter__()
set1 = {1, 2, 3}
set1.__iter__()
with open('a.txt', mode='w') as f:
f.__iter__()
可迭代对象调用__iter__
方法会将其转换成迭代器对象。
l1 = [1, 2, 3, 4]
res1 = l1.__iter__()
print(res1)
<list_iterator object at 0x1081a2ee0>
迭代器对象拥有__next__
方法,调用一次__next__
方法,返回迭代器对象的下一个值,直至取完报错,即迭代取值
d1 = {'a': 1, 'b': 2}
iterator1 = d1.__iter__()
print(iterator1.__next__())
print(iterator1.__next__())
print(iterator1.__next__())
a
b
Traceback (most recent call last):
File "/Users/laobai/Pycharm_2022/study_test03/temp/test01.py", line 152, in <module>
print(iterator1.__next__())
StopIteration
迭代器协议:对象需要提供__next__
方法,它要么返回迭代中的下一个值,要么引起一个StopIteration
异常,以终止迭代;
for循环的工作原理
示例代码:
dict1={'a':1,'b':2,'c':3}
for k in dict1:
print(k)
执行结果:
a
b
c
for循环的步骤:
in
后面的内容dict1
会自动执行dict1.__iter__()
得到一个迭代器对象迭代器对象.__next__()
拿到一个返回值,然后将该返回值赋值给k
- 循环步骤2,直至最后一个值结束,抛出
StopIteration
异常,for循环会捕捉异常然后结束循环
生成器
生成器
使用了yield
的函数,被调用后,不会执行函数体,而是返回一个生成器对象,只能用于迭代操作,这样的函数被称为生成器,既被称为自定义的迭代器。在调用生成器运行的过程中,每次遇到yield
时函数会暂停并保存当前所有的运行信息,返回yield
的值,并在下一次执行next()
方法时从当前位置继续执行。
def func():
print('第一个')
yield 1
print('第二个')
yield 2
print('第三个')
yield 3
print('第四个')
g = func()
# g.__next__()会触发函数体代码的运行,然后遇到yield停下来,
# 将yield后的值当做本次调用的结果返回
res1 = g.__next__()
print(res1)
res2 = g.__next__()
print(res2)
res3 = g.__next__()
print(res3)
res4 = g.__next__()
print(res4)
运行结果:
第一个
1
第二个
2
第三个
3
第四个
Traceback (most recent call last):
File "/Users/laobai/Pycharm_2020/study2021/20210515/test4.py", line 40, in <module>
res4 = g.__next__()
StopIteration
上面的代码中
res1 = g.__next__()
可以写成
res1 = next(g)
生成器示例
def my_range(start,stop,step=1):
while start < stop:
yield start
start += step
g = my_range(1,5,2)
print(next(g))
print(next(g))
print(next(g))
1
3
Traceback (most recent call last):
File "/Users/laobai/test4.py", line 53, in <module>
print(next(g))
StopIteration
生成器表达式
l1 = []
for x in range(10):
l1.append(x * x)
print(l1)
l2 = [x * x for x in range(10)]
print(l2)
g1 = (x * x for x in range(10))
print(g1)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
<generator object <genexpr> at 0x10cb8be40>
yield表达式
程序运行到yield关键字就会停下运行,需要通过next()或send()等方法从上次停止的yield关键字再次运行。
def dog(name):
print('大黄狗%s准备吃东西了。。。'%name)
while True:
x = yield # x是函数外部通过shed()传给yield的值
print("大黄狗%s吃了 %s" %(name,x))
g=dog('小猫')
g.send(None) # 等同于next(g) 刚刚定义好的生成器需要先为yield传一个None进行初始化
g.send('一根骨头')
g.send('狗不理包子')
g.send('大黄鱼')
g.close() # 关闭之后,就无法传值了(send())
运行结果:
大黄狗小猫准备吃东西了。。。
大黄狗小猫吃了 一根骨头
大黄狗小猫吃了 狗不理包子
大黄狗小猫吃了 大黄鱼
在上面的例子基础上,增加yield返回值 food_list列表,代码如下:
def dog(name):
food_list=[]
print('大黄狗%s准备吃东西了。。。'%name)
while True:
x = yield food_list # x是函数外部通过shed()传给yield的值
print("大黄狗%s吃了 %s" %(name,x))
food_list.append(x)
g=dog('小猫')
res1=g.send(None) # 等同于next(g) 刚刚定义好的生成器需要先为yield传一个None进行初始化
print(res1)
res2=g.send('一根骨头')
print(res2)
res3=g.send('狗不理包子')
print(res3)
res4=g.send('大黄鱼')
print(res4)
g.close() # 关闭之后,就无法传值了(send())
执行结果:
大黄狗小猫准备吃东西了。。。
[]
大黄狗小猫吃了 一根骨头
['一根骨头']
大黄狗小猫吃了 狗不理包子
['一根骨头', '狗不理包子']
大黄狗小猫吃了 大黄鱼
['一根骨头', '狗不理包子', '大黄鱼']