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