【Python生成器详解】


一、前言

在 Python 中,生成器(Generator)是一种特殊的迭代器,通过 yield 关键字生成值,具备惰性求值特性。这意味着生成器在每次迭代时计算下一个值,而不是一次性生成所有值。与普通列表相比,生成器更节省内存,适合处理大数据流或无限序列。


二、生成器的定义与使用

1. 使用 yield 关键字创建生成器

在 Python 中,生成器本质上是带有 yield 语句的函数。当函数包含 yield 时,每次调用生成器的 next() 方法时,函数会从上次暂停的地方继续执行。

✅ 示例:生成 Fibonacci 序列

def fibonacci(n):
    """生成 n 个 Fibonacci 数列"""
    a, b = 0, 1
    for _ in range(n):
        yield a
        a, b = b, a + b

# 使用生成器
gen = fibonacci(5)

# 逐个获取生成器中的值
print(next(gen))  # 0
print(next(gen))  # 1
print(next(gen))  # 1
print(next(gen))  # 2
print(next(gen))  # 3

解释:

  • yield 会将当前值返回,并在当前位置暂停。
  • 下次调用 next() 时,从暂停位置继续执行。
  • 生成器不会立即计算所有值,仅在迭代时生成数据,节省内存。

yieldreturn 区别

  • return:终止函数并返回值。
  • yield:在暂停位置保存状态,并返回当前值。

示例:

def example_return():
    return 1
    return 2  # 不会被执行

def example_yield():
    yield 1
    yield 2  # 可以多次返回

print(list(example_return()))  # [1]
print(list(example_yield()))   # [1, 2]

三、生成器表达式与列表解析

Python 提供了一种简洁的生成器表达式语法,类似于列表解析,但使用 () 而不是 []

✅ 列表解析与生成器表达式对比

# 列表解析:一次性生成所有元素
lst = [x**2 for x in range(5)]
print(lst)  # [0, 1, 4, 9, 16]

# 生成器表达式:按需生成元素
gen = (x**2 for x in range(5))
print(gen)           # <generator object>
print(list(gen))     # [0, 1, 4, 9, 16]

区别:

  • 列表解析会立即生成所有元素,占用内存。
  • 生成器表达式惰性求值,按需生成元素,节省内存。

四、生成器方法:next()send()

1. next() 方法

  • next() 用于从生成器中获取下一个元素。
  • 如果元素耗尽,则抛出 StopIteration 异常。

✅ 示例:

def counter():
    n = 0
    while n < 3:
        yield n
        n += 1

gen = counter()

print(next(gen))  # 0
print(next(gen))  # 1
print(next(gen))  # 2
# print(next(gen))  # 抛出 StopIteration 异常

2. send() 方法

  • send(value) 可向生成器发送值,并将其赋给 yield 表达式。
  • next() 不同,send() 可以与生成器交互,传递外部值。

✅ 示例:

def gen():
    x = 0
    while True:
        x = yield x
        print(f"Received: {x}")

g = gen()

print(next(g))      # 初始化生成器:0
print(g.send(10))   # Received: 10 → 返回 10
print(g.send(20))   # Received: 20 → 返回 20

五、生成器提高性能与应用

1. 节省内存

生成器适合处理大数据集或无限序列,因为它们不会将数据全部存入内存。

✅ 示例:生成百万整数

import sys

# 列表方式
lst = [i for i in range(10**6)]
print(f"List占用内存: {sys.getsizeof(lst)} 字节")

# 生成器方式
gen = (i for i in range(10**6))
print(f"Generator占用内存: {sys.getsizeof(gen)} 字节")

输出:

List占用内存: 8697464 字节  
Generator占用内存: 112 字节  

生成器显著减少了内存占用。

2. 文件读取处理

生成器可以高效地逐行读取大文件,避免一次性将数据加载到内存中。

✅ 示例:

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

# 使用生成器逐行读取
for line in read_large_file('large_file.txt'):
    print(line)

六、生成器使用案例

1. 无限序列生成

生成器可以创建无限序列,而不会耗尽内存。

✅ 示例:生成无限斐波那契数列

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

# 无限生成斐波那契数列
fib = infinite_fib()
for _ in range(10):
    print(next(fib), end=" ")  # 0 1 1 2 3 5 8 13 21 34

2. 并行任务调度

生成器可用于协程,实现简易的任务调度。

✅ 示例:

import time

def task1():
    for i in range(3):
        print(f"Task 1 - {i}")
        yield
        time.sleep(1)

def task2():
    for i in range(3):
        print(f"Task 2 - {i}")
        yield
        time.sleep(1)

# 并行执行任务
t1 = task1()
t2 = task2()

for _ in range(3):
    next(t1)
    next(t2)

七、总结

  • 生成器通过 yield 实现惰性求值,按需生成数据,节省内存。
  • return 不同,yield 会在暂停位置恢复执行。
  • 使用 send() 方法可与生成器进行双向通信。
  • 生成器适合处理大数据、流数据或无限序列,显著提高程序性能。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wdwc2

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值