生成器

Python生成器(Generator)教程

什么是生成器

生成器(Generator)是Python中一种特殊的迭代器,它允许你按需生成值,而不是一次性生成所有值并存储在内存中。这在处理大数据集或无限序列时特别有用。

生成器的主要特点:

  • 按需生成值,节省内存
  • 保持状态,可以暂停和恢复执行
  • 语法简洁,易于实现

创建生成器的两种方法

1. 生成器表达式

生成器表达式与列表推导式类似,但使用圆括号()而不是方括号[]

# 列表推导式 - 立即生成所有元素
list_comp = [x**2 for x in range(10)]

# 生成器表达式 - 按需生成元素
gen_exp = (x**2 for x in range(10))

生成器表达式适用于简单的转换和过滤操作。

2. 生成器函数

使用yield关键字定义的函数就是生成器函数:

def count_up_to(max):
    count = 1
    while count <= max:
        yield count
        count += 1

生成器函数在每次调用next()时执行到下一个yield语句,然后暂停,保持所有局部变量的状态。

生成器的使用

基本迭代

# 使用for循环迭代
for num in count_up_to(5):
    print(num)

手动控制

gen = count_up_to(3)
print(next(gen))  # 输出: 1
print(next(gen))  # 输出: 2
print(next(gen))  # 输出: 3
print(next(gen))  # 抛出StopIteration异常

生成器的高级特性

1. 生成器状态

生成器保持其执行状态,包括局部变量和指令指针:

def stateful_gen():
    print("开始执行")
    yield 1
    print("继续执行")
    yield 2
    print("结束执行")

gen = stateful_gen()
next(gen)  # 输出"开始执行",返回1
next(gen)  # 输出"继续执行",返回2
next(gen)  # 输出"结束执行",抛出StopIteration

2. 生成器返回值

Python 3.3+允许生成器使用return返回值:

def gen_with_return():
    yield 1
    yield 2
    return "完成"

gen = gen_with_return()
try:
    while True:
        print(next(gen))
except StopIteration as e:
    print(e.value)  # 输出: "完成"

3. 生成器委托(Python 3.3+)

使用yield from可以委托给另一个生成器:

def chain_generators(*iterables):
    for it in iterables:
        yield from it

gen = chain_generators([1, 2], (3, 4), "ab")
list(gen)  # 返回 [1, 2, 3, 4, 'a', 'b']

实际应用示例

1. 斐波那契数列生成器

def fibonacci():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

fib = fibonacci()
for _ in range(10):
    print(next(fib))

2. 读取大文件

def read_large_file(file_path):
    with open(file_path, 'r') as file:
        for line in file:
            yield line.strip()

# 逐行处理大文件,不占用过多内存
for line in read_large_file('huge_file.txt'):
    process_line(line)

3. 无限序列

def natural_numbers():
    n = 1
    while True:
        yield n
        n += 1

nums = natural_numbers()
for _ in range(5):
    print(next(nums))  # 1, 2, 3, 4, 5

生成器与协程

Python的生成器也可以用于协程编程,通过.send()方法可以向生成器发送值:

def coroutine():
    print("启动协程")
    while True:
        value = yield
        print(f"接收到值: {value}")

co = coroutine()
next(co)  # 启动协程
co.send(10)  # 输出: "接收到值: 10"
co.send(20)  # 输出: "接收到值: 20"

性能考虑

  • 内存效率:生成器按需生成值,适合处理大数据集
  • 速度:生成器通常比列表推导式慢,但内存占用更少
  • 一次性使用:生成器只能迭代一次,如果需要多次使用,可以转换为列表或重新创建生成器

练习题:杨辉三角生成器

def triangles():
    row = [1]
    while True:
        yield row
        row = [1] + [row[i] + row[i+1] for i in range(len(row)-1)] + [1]

# 测试
results = []
n = 0
for t in triangles():
    results.append(t)
    n += 1
    if n == 10:
        break

for row in results:
    print(row)

总结

生成器是Python中强大的工具,特别适合:

  • 处理大数据集
  • 实现无限序列
  • 构建数据处理管道
  • 协程编程

掌握生成器可以显著提高代码的内存效率,并使你的Python代码更加Pythonic。