生成器与迭代器

📅 2026/7/7 4:57:42 👁️ 阅读次数 📝 编程学习
生成器与迭代器

迭代器(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帮你做。
  • 因此生成器也是一种特殊的迭代器。
定义方式:
  1. 使用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 关键字
    • 暂停
    • 返回当前值
    • 下次从暂停位置继续
  1. 生成器表达式(类似列表推导式)
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的区别

特性returnyield
函数性质普通函数生成器函数 (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)) # 输出: 第二步 (函数从刚才暂停的地方恢复)