迭代器,生成器
迭代器
迭代器:迭代的工具。迭代是更新换代,迭代也可以说成是重复,并且每一次的重复都是基于上一次的结果来的。如计算机中的迭代开发,就是基于软件的上一个版本更新。以下代码就不是迭代,它只是单纯的重复。
# 纯粹的重复
while True:
print('我只是一个重复的过程')
可迭代的对象
可迭代对象:只要具有 _inter_ 方法的数据类型,都是可迭代对象。
# 字符串
st = 'zkim'
print(st.__iter__())
# 列表
l = [1,2,3]
print(l.__iter__())
# 元组
t = (1,2,3)
print(t.__iter__())
# 字典
d = {'name':'zkim','age':18}
print(d.__iter__())
# 集合
se = {1,2,3}
print(se.__iter__())
# 文件
f = open('xxx','w',encoding='utf-8')
print(f.__iter__())
f.close()
# <str_iterator object at 0x000000B2AC1EC3C8>
# <list_iterator object at 0x000000B2AC1EC358>
# <tuple_iterator object at 0x000000B2AC1EC390>
# <dict_keyiterator object at 0x000000B2AC1585E8>
# <set_iterator object at 0x000000B2AC1E9BD0>
# <_io.TextIOWrapper name='xxx' mode='w' encoding='utf-8'>
可迭代对象使用 _iter_ 的方法,可以拿到一个返回值,这个返回值就是迭代器对象。
迭代器对象
数据类型中,字符串,列表,元祖都是依赖索引取值的。在这里我们又学到了一个可以不依赖索引,就能取值的方法。(迭代器对象)
迭代器对象:既有内置 _inter_ 方法,又有内置 _next_ 方法的数据类型。
注意:当某一个数据类型中的值,依次被取完之后,如果再取的话就会报错。错误:StopIteration
# 文件类型的数据既有__iter__,又有__next__,所以文件本身就是迭代器对象。
f = open('text.txt','r',encoding='utf-8')
f.__iter__()
f.__next__()
# 字符串
st = 'zkim'
res = st.__iter__()
print(res.__next__())
print(res.__next__())
# 列表
l = [1,2,3]
res1 = l.__iter__()
print(res1.__next__())
print(res1.__next__())
# 元祖
t = (1,2,3)
res2 = t.__iter__()
print(res2.__next__())
print(res2.__next__())
# 字典
d = {'name':'zkim','age':18}
res3 = d.__iter__()
print(res3.__next__())
print(res3.__next__())
# 集合
se = {1,2,3}
res4 = se.__iter__()
print(res4.__next__())
print(res4.__next__())
# z
# k
# 1
# 2
# 1
# 2
# name
# age
# 1
# 2
注意:当某一个数据类型中的值,依次被取完之后,如果再取的话就会报错。错误:StopIteration
l = [1,2]
res = l.__iter__()
print(res.__next__())
print(res.__next__())
print(res.__next__())
# StopIteration
在上述的方法中没取一个值就得 _next_ 一次,特别的繁琐,所以我们可以用 while 循环来精简下。为了防止报错可以使用异常捕捉: try...except... 来处理
l = [1,2,3]
iter_l = l.__iter__()
while True:
try:
print(iter_l.__next__())
except StopIteration:
break
# 1
# 2
# 3
- 总结:
迭代器对象:执行可迭代对象的 _inter_ 方法,拿到的返回值就是迭代器对象。
- 特点:
1:内置 _next_ 方法,执行该方法会拿到迭代器对象中的一个值。
2:内置有 _iter_ 方法,执行该方法会拿到迭代器对象。
3:文件本身就是迭代器对象。
- 优点:
1:不依赖索引取值。
2:内存中永远只占一份空间,不会导致内存溢出。
- 缺点:
1:取值麻烦,不能获取指定的值,并且只能往后取。
2:取完之后会报 StopIteration 的错误。
for 循环内部原理
for 循环称之为迭代器循环, in 后面接的必须是可迭代对象。
- for 循环内部的本质:
1:将 in 后的对象调用 _iter_ 转换成迭代器对象
2:调用 _next_ 迭代取值
3:内部有异常捕获 StopIteration,当 _next_ 报这个粗时,会自动结束循环。
l = [1,2,3]
for i in l:
print(i)
# 1
# 2
# 3
生成器
生成器:用户自定义的迭代器,本质就是迭代器。
- 关键字 yield
1:帮你提供了一种自定义生成器的方式。
2:可以将函数体代码的运行暂停。
3:可以返回值
# 自定义的迭代器:生成器,是定义在函数内部的,利用 yield 关键字,将函数自定义成一个生成器
def func():
print('我是第一个')
yield 1
print('我是第二个')
yield 2
g = func() # 在调用函数的时候,有 yield 的情况下不会执行函数体代码
print(g.__next__()) # 执行到 yield 1 的时候暂停
print(g.__next__()) # 执行到 yield 2 的时候暂停
# 只有在调用的时候才会依次往下执行。
# 我是第一个
# 1
# 我是第二个
# 2
# yield 可以接收外部的值
def shopping(shop):
print('%s 已被购买'%shop)
while True:
people = yield
print('%s 被 %s 购买'%(shop,people))
res = shopping('法拉利')
res.__next__()
res.send('鸡哥')
# 法拉利 已被购买
# 法拉利 被 鸡哥 购买
- 与 return 的异同之处
相同点:
都可以返回值,并且都可以返回多个值。
不同点:
yield 可以返回多次值,而 return 只能返回一次后函数立即结束。
yield 还可以接受外部传入的值。
生成器表达式
res = (i for i in range(1,3) if i != 4)
print(res)
print(res.__next__())
print(res.__next__())
# <generator object <genexpr> at 0x0000000BA3EAB728>
# 1
# 2