一个简单的Python案例能否帮你搞懂生成器

访客 python案例 6

本文目录导读:

  1. 核心概念
  2. 案例1:最简单的生成器
  3. 案例2:经典斐波那契数列
  4. 案例3:用 next() 手动控制
  5. 为什么能“省内存”?—— 本质对比
  6. 关键理解

我们来通过一个简单的案例,彻底搞懂 Python 生成器

生成器的核心思想是惰性求值(Lazy Evaluation):它不一次性生成所有数据,而是在你需要的时候才一个接一个地“生产”出来,这能极大地节省内存。

核心概念

  1. yield 关键字:生成器函数里用 yield 代替 return
  2. 状态保留:每次调用 next() 时,函数从上次 yield 退出的地方继续执行。
  3. next() 函数:手动获取下一个值。
  4. for 循环:自动获取所有值(更常用)。

案例1:最简单的生成器

对比生成列表和生成器,看内存差异。

# 1. 普通函数:返回一个列表(一次性创建所有数据)
def get_squares_list(n):
    squares = []
    for i in range(n):
        squares.append(i * i)
    return squares
# 2. 生成器函数:每次yield一个值
def get_squares_generator(n):
    for i in range(n):
        yield i * i      # 每次生成一个,暂停在这里
# --- 使用对比 ---
print("普通列表:")
list_result = get_squares_list(5)   # 立即创建 [0, 1, 4, 9, 16]
print(list_result)                  # 输出完整列表
print("\n生成器:")
gen_result = get_squares_generator(5)  # 创建了一个生成器对象,还没有计算任何值!
print(gen_result)                    # 输出:<generator object ...>
# 用for循环逐个取出来(自动调next)
for value in gen_result:
    print(value, end=' ')   # 输出:0 1 4 9 16

案例2:经典斐波那契数列

对比普通函数和生成器的内存消耗。
假设要“生成第1亿个斐波那契数后的100个数”——普通列表会炸内存,生成器毫发无伤。

# 生成器方式:每次只记得前两个数,不保留整个序列
def fibonacci_generator(limit):
    a, b = 0, 1
    count = 0
    while count < limit:
        yield a          # 返回当前值,暂停
        a, b = b, a + b
        count += 1
print("斐波那契数列前10项:")
for num in fibonacci_generator(10):
    print(num, end=' ')  # 0 1 1 2 3 5 8 13 21 34
# 如果极限值很大(比如10^8),普通列表会崩溃,但生成器只占用极少内存

案例3:用 next() 手动控制

有时候你不想一次全取完,可以“走一步看一步”。

def countdown(start):
    while start > 0:
        yield start
        start -= 1
    yield "Go!"
gen = countdown(3)
print("手动调用next:")
print(next(gen))  # 3
print(next(gen))  # 2
print(next(gen))  # 1
print(next(gen))  # Go!
# 如果再调一次 next(gen),会触发 StopIteration 异常(for循环会自动处理)

为什么能“省内存”?—— 本质对比

特性 普通列表(return [...] 生成器(yield
数据存储 全部在内存中 一次只存一个值
读取方式 可以索引、切片、反复使用 只能单向遍历,用后即忘
适用场景 数据量小,需要随机访问 数据量大,只需顺序处理
性能 创建快,但不适合超大序列 创建极快,几乎不占额外内存

关键理解

  • 生成器不是“一次性计算所有结果的函数”,而是可暂停的函数
  • 每次 yield 就像函数对你说:“给你一个值,我先歇会儿,下次你再叫我,我接着干。”
  • 你用 for 循环时,Python 自动不断地 next() 它,直到没有 yield 了。

需要处理海量数据但又不想让内存爆炸时,用生成器,它是“按需生产”的懒人神器。

你可以把上面代码复制到 Python 里跑一遍,重点看生成器 print(gen_result) 的输出——它只是一个对象,没有数字,再对比 list_result 已经占了一大块内存,这就是区别。

标签: Python

抱歉,评论功能暂时关闭!