用自己的理解来解释一下迭代器和生成器。
在 Python 中,迭代器(Iterator)和生成器(Generator)均用于遍历集合中的元素。二者皆为实现迭代协议的对象。
迭代器: 是遵循特定协议的对象,具体来说就是实现了 __iter__()
和 __next__()
方法的对象。通过这些方法,迭代器能够逐次提供序列中的项直到耗尽为止,在此过程中如果尝试获取超出范围的数据,则会抛出 StopIteration
异常作为结束信号。
再简单理解就是,一个类里面,有 __iter__()
和 __next__()
这两个方法,在类实例化之后,可以调用这两个方法。直到类里面设置的元素被访问完然后报错,抛出 StopIteration
异常作为结束信号。
生成器: 则是一类特殊的迭代器,由含有 yield
表达式的函数创建而成。每当遇到 yield
语句时,程序状态会被冻结直至下次激活;此时可以从上次暂停的地方恢复执行流程,并返回相应的值给调用者。因此可以说每次调用生成器实际上是在请求其内部逻辑产生的下一个项目。
简单的说就是,在一个函数中,里面有return这个关键字,换成了yield这个关键字,有了这个yield关键字就有种让程序暂停的状态。
特性 | 迭代器 (Iterator) | 生成器 (Generator) |
---|---|---|
创建方式 | 可以手动编写类并重写两个特殊的方法(__iter__() , __next__() ) 或者利用内建函数如 iter() 对象转换而来 |
定义带有至少一个 yield 的函数即可形成生成器表达式或直接写出完整的生成器函数 |
返回机制 | 调用 __next__() 获取单个元素 |
执行至 yield 处停止并将控制权交还给外部环境 |
存储形式 | 需要预先准备好整个数据集 | 动态计算每一项而不必事先全部存入内存 |
迭代器:
# 元组可迭代数据类型
i = iter((1,2,3)) # 调用 iter()方法,获得迭代器对象
print(type(i)) # 打印数据类型
print(next(i))
print(next(i)) # 调用 next()方法,获得下一个迭代器对象
print(next(i))
print(next(i))
# 结果
1
2
3
# 异常:
Traceback (most recent call last):
File "D:/Pycharm Perject save path/python/CeShi.py", line 19, in
print(next(i))
StopIteration
# 异常原因:
元组内的元素一共是 3 个,而我调用了 4 次 next()方法,每次都会返回一个元素,
当没有元素可以返回的时候,就会自动抛出异常 StopIteration 。
生成器:
def odd():
n = 1
while True:
yield n # yield 关键字
n += 1
odd_num = odd() # 把odd()的返回值用一个变量来保存
print(odd_num)
print(odd_num.__next__())
print(odd_num.__next__())
print(odd_num.__next__())
/Users/bytedance/Desktop/.venv/bin/python /Users/bytedance/Desktop/111.py
1
2
3
# 自定义迭代器示例
class MyRange:
def __init__(self, start, end):
self.current = start
self.end = end
def __iter__(self): # 实现迭代器接口之一
return self # 返回自身作为一个迭代器对象
def __next__(self): # 实现迭代器接口之二
if self.current >= self.end:
raise StopIteration # 抛出异常表示已经到达终点
else:
result = self.current
self.current += 1
return result # 正常情况下返回当前索引对应的数值
for i in MyRange(0, 5):
print(i)
# 生成器函数版本
def my_range(start, end):
current = start
while current < end:
yield current # 使用 yield 替换了之前的 return ,使得函数成为了一个生成器
current += 1 # 更新计数器以便下一轮循环使用
gen_obj = my_range(0, 5)
print(next(gen_obj)) # 显示第一个产出的结果
print(list(my_range(0, 5))) # 将所有可能的输出收集起来放入列表中打印出来
暂无