yield 是 Python 中一个非常重要的关键字,它用于创建生成器函数。生成器函数可以暂停和恢复执行,使得它们能够高效地处理大数据集或无限序列。

基础概念

  1. 生成器函数 vs 普通函数
# 普通函数
def normal_function(n):
    result = []
    for i in range(n):
        result.append(i * i)
    return result

# 生成器函数
def generator_function(n):
    for i in range(n):
        yield i * i

# 使用普通函数
print("普通函数结果:", normal_function(5))  # [0, 1, 4, 9, 16]

# 使用生成器函数
gen = generator_function(5)
print("生成器结果:", list(gen))  # [0, 1, 4, 9, 16]
  1. yield 的工作原理
def simple_generator():
    print("开始执行")
    yield 1
    print("继续执行")
    yield 2
    print("结束执行")

# 创建生成器对象
gen = simple_generator()

# 第一次调用 next()
print("第一次调用:")
value1 = next(gen)  # 输出: 开始执行
print(f"得到值: {value1}")  # 得到值: 1

# 第二次调用 next()
print("第二次调用:")
value2 = next(gen)  # 输出: 继续执行
print(f"得到值: {value2}")  # 得到值: 2

# 第三次调用 next() 会抛出 StopIteration 异常
try:
    value3 = next(gen)  # 输出: 结束执行
except StopIteration:
    print("生成器已耗尽")

实际应用示例

  1. 读取大文件
def read_large_file(file_path):
    """逐行读取大文件,避免内存溢出"""
    with open(file_path, 'r', encoding='utf-8') as file:
        for line in file:
            yield line.strip()

# 使用示例
for line in read_large_file('large_file.txt'):
    # 处理每一行数据
    print(line)
    # 不需要一次性加载整个文件到内存
  1. 生成无限序列
def fibonacci():
    """生成斐波那契数列"""
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

# 使用示例
fib_gen = fibonacci()
for i in range(10):
    print(next(fib_gen))  # 输出前10个斐波那契数
  1. 管道数据处理
def numbers(n):
    for i in range(n):
        yield i

def square(nums):
    for num in nums:
        yield num ** 2

def filter_even(nums):
    for num in nums:
        if num % 2 == 0:
            yield num

# 构建数据处理管道
result = filter_even(square(numbers(10)))
print(list(result))  # [0, 4, 16, 36, 64]

高级用法

  1. 使用 send() 方法与生成器交互
def interactive_generator():
    value = 0
    while True:
        # yield 可以接收外部发送的值
        received = yield value
        if received is not None:
            value = received
        else:
            value += 1

gen = interactive_generator()
print(next(gen))  # 0
print(gen.send(10))  # 10
print(next(gen))  # 11
print(next(gen))  # 12
  1. 使用 yield from 委托生成器
def sub_generator():
    yield from range(3)
    yield from ['a', 'b', 'c']

def main_generator():
    yield "开始"
    yield from sub_generator()
    yield "结束"

for item in main_generator():
    print(item)
# 输出: 开始, 0, 1, 2, a, b, c, 结束
  1. 协程实现
def coroutine():
    while True:
        received = yield
        print(f"收到: {received}")

# 创建协程
co = coroutine()
next(co)  # 启动协程

co.send("Hello")  # 收到: Hello
co.send("World")  # 收到: World

实现原理模拟

为了更好地理解 yield 的工作原理,我们可以模拟一个简单的生成器:

class SimpleGenerator:
    """模拟生成器行为的类"""
    
    def __init__(self, n):
        self.n = n
        self.current = 0
        self.state = "created"
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.state == "finished":
            raise StopIteration
        
        if self.current < self.n:
            result = self.current ** 2
            self.current += 1
            return result
        else:
            self.state = "finished"
            raise StopIteration

# 使用模拟的生成器
fake_gen = SimpleGenerator(5)
for value in fake_gen:
    print(value)  # 输出: 0, 1, 4, 9, 16

性能对比

import time
import sys

def regular_list(n):
    result = []
    for i in range(n):
        result.append(i * i)
    return result

def generator_version(n):
    for i in range(n):
        yield i * i

# 内存使用对比
n = 1000000

# 列表版本
start = time.time()
list_result = regular_list(n)
list_memory = sys.getsizeof(list_result)
list_time = time.time() - start

# 生成器版本
start = time.time()
gen_result = generator_version(n)
gen_memory = sys.getsizeof(gen_result)
gen_time = time.time() - start

print(f"列表版本 - 时间: {list_time:.4f}s, 内存: {list_memory} 字节")
print(f"生成器版本 - 时间: {gen_time:.4f}s, 内存: {gen_memory} 字节")

总结

yield 关键字是 Python 中实现生成器的核心,它提供了:

  1. 内存效率:按需生成值,避免一次性加载所有数据到内存
  2. 惰性求值:只在需要时计算值
  3. 状态保持:函数执行状态在 yield 之间保持
  4. 代码简洁:使用简洁的语法实现复杂的迭代逻辑

生成器是 Python 中处理大数据集、实现协程和构建数据处理管道的强大工具。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐