在Python中,迭代器和生成器是处理数据流的灵魂,它们的核心目标只有一个------------节省内存。
迭代器(Iterator)
直观解释:
- 迭代器就是能够将一堆数据一个个吐出来的对象,而不是一次性输出。
- 比如:
python
复制代码
nums = [1, 2, 3]
it = iter(nums) # 获取迭代器
print(next(it)) # 1
print(next(it)) # 2
print(next(it)) # 3
本质定义:
- 任何一个对象要想成为迭代器,需要满足以下两个方法:
python
复制代码
__iter__() # 返回自身
__next__() # 返回容器的下一个元素。如果没有元素了,则抛出 StopIteration 异常。
自定义生成器
python
复制代码
class MyIterator:
def __init__(self, n):
self.n = n
self.cur = 0
def __iter__(self):
return self
def __next__(self):
if self.cur < self.n:
self.cur += 1
return self.cur
else:
raise StopIteration
if __name__ == '__main__':
it = MyIterator(3)
for i in it:
print(i)
特点:
- 惰性计算(用一个取一个)
- 节省内存
- 只能往前走,不能回退
生成器(Generator)
直观理解:
- 生成器是"自动帮你写好的迭代器"。不用写 next,Python帮你做。
- 因此生成器也是一种特殊的迭代器。
定义方式:
- 使用yield关键字
python
复制代码
def gen():
yield 1
yield 2
yield 3
if __name__ == '__main__':
g = gen()
print(g)
print(next(g))
print(next(g))
print(next(g))
- 生成器表达式(类似列表推导式)
python
复制代码
g = (x*x for x in range(5))
python
复制代码
[x*x for x in range(5)] # 列表(一次性全部生成)
(x*x for x in range(5)) # 生成器(按需生成)
两者对比
| 对比点 |
迭代器 |
生成器 |
| 定义方式 |
类实现 |
yield / 表达式 |
| 实现难度 |
高 |
非常简单 |
| 本质 |
手写迭代逻辑 |
自动生成迭代器 |
| 是否惰性 |
是 |
是 |
| 是否是迭代器 |
✔ |
✔(生成器本身就是迭代器) |
可迭代对象 (Iterable)
- 可迭代对象 (Iterable): 像 list, dict, str 这种可以用 for 循环遍历的都是可迭代对象,但它们不是迭代器。
- Python 规定:一个对象内部实现了 iter() 方法,就是可迭代对象。
- 转换: 可以用 iter() 函数把可迭代对象转成迭代器。
三者之间的关系:
text
复制代码
可迭代对象 Iterable
↓ 调用 __iter__() 可以得到
迭代器 Iterator
↓ 生成器是它的子类
生成器 Generator
yield和return的区别
| 特性 |
return |
yield |
| 函数性质 |
普通函数 |
生成器函数 (Generator) |
| 退出机制 |
彻底结束:函数执行完毕,销毁局部变量 |
暂停执行:挂起函数,保存当前所有状态 |
| 返回值次数 |
只能返回 1 次(或者返回一个包含多数据的元组) |
可以返回多次(每次调用返回一个值) |
| 状态保存 |
不保存状态,下次调用从头开始 |
自动保存:下次调用从上次停止的地方继续 |
| 内存占用 |
高(一次性返回所有数据) |
低(按需生成,一次只占一个值的空间) |
举例:
- 当你调用一个带 return 的函数时,它会从第一行开始运行,直到遇到 return。一旦 return 执行,函数就把结果扔给调用者,然后原地解散,内存中的局部变量全部回收。
python
复制代码
def normal_func():
return "第一步"
return "第二步" # 永远不会被执行
print(normal_func()) # 输出: 第一步
- 当你调用带 yield 的函数时,它并不会立即执行代码,而是返回一个生成器对象。每次你对这个对象执行 next(),它就运行到下一个 yield 处,把值交给你,然后原地休眠。它会记住所有的变量、当前的循环进度和执行行数。
python
复制代码
def generator_func():
yield "第一步"
yield "第二步"
yield "第三步"
gen = generator_func()
print(next(gen)) # 输出: 第一步 (函数在此处暂停)
print(next(gen)) # 输出: 第二步 (函数从刚才暂停的地方恢复)
- 在 Python 3.3 之后,同一个函数里可以同时出现 return 和 yield:
- yield 负责产生数据流。
- return 负责彻底结束生成器。如果在生成器中执行了 return value,这实际上会引发一个 StopIteration 异常,并将 value 作为异常的说明信息。