Python之迭代器和生成器


迭代器

迭代器指的是迭代取值的工具,迭代是一个重复的过程,每次重复都是基于上一次的结果而继续的,单纯的重复并不是迭代。

可迭代对象:内置有__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循环的步骤:

  1. in后面的内容dict1会自动执行dict1.__iter__() 得到一个迭代器对象
  2. 迭代器对象.__next__() 拿到一个返回值,然后将该返回值赋值给k
  3. 循环步骤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())

执行结果:

大黄狗小猫准备吃东西了。。。
[]
大黄狗小猫吃了 一根骨头
['一根骨头']
大黄狗小猫吃了 狗不理包子
['一根骨头', '狗不理包子']
大黄狗小猫吃了 大黄鱼
['一根骨头', '狗不理包子', '大黄鱼']

文章作者: 老百
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 老百 !
 上一篇
Python之装饰器 Python之装饰器
装饰器(Decorator)是Python中一个重要部分,它本质上是一个函数,不同于普通函数,装饰器的返回值是一个函数对象。通过利用装饰器,我们可以让其他函数在不做任何代码改动的情况下增加额外的功能,同时也能够让代码更加简洁。
2022-10-11
下一篇 
Python之函数 Python之函数
Python函数是指组织好的、可重复使用的、用来实现单一或相关联功能的代码段。Python函数包含系统中自带的一些函数、第三方函数、以及用户自定义的函数。
2022-10-07
  目录