Python中的生成器(Generator)与协程(Coroutine)的区别与联系
字数 795 2025-11-26 12:58:12
Python中的生成器(Generator)与协程(Coroutine)的区别与联系
生成器和协程都是Python中重要的编程概念,它们都使用yield关键字,但在设计目的和使用方式上有本质区别。
1. 生成器的基本概念
生成器是一种特殊的迭代器,用于按需生成值,节省内存空间。
def simple_generator():
yield 1
yield 2
yield 3
# 使用生成器
gen = simple_generator()
print(next(gen)) # 输出: 1
print(next(gen)) # 输出: 2
2. 生成器的工作方式
- 生成器函数执行到
yield时暂停,返回 yield 后面的值 - 下次调用
next()时从暂停处继续执行 - 主要用于数据的惰性生成
3. 协程的基本概念
协程是更一般的子程序,可以在多个点暂停和恢复,支持双向数据传递。
def simple_coroutine():
print("协程启动")
x = yield # 可以接收外部发送的值
print(f"接收到: {x}")
coro = simple_coroutine()
next(coro) # 启动协程,输出"协程启动"
coro.send(42) # 发送数据到协程,输出"接收到: 42"
4. 关键区别详解
4.1 数据流方向
- 生成器:单向数据流(生产者→消费者)
- 协程:双向数据流(既可以产出数据,也可以消费数据)
# 生成器示例(单向)
def number_generator(n):
for i in range(n):
yield i # 只产出数据
# 协程示例(双向)
def calculator():
result = 0
while True:
x = yield result # 既接收数据,也产出数据
result += x
4.2 yield关键字的使用位置
- 生成器:yield通常作为语句使用
- 协程:yield作为表达式使用,可以接收值
4.3 设计目的
- 生成器:主要用于创建迭代器,处理数据序列
- 协程:用于并发编程,实现协作式多任务
5. 演进关系
Python中的协程是从生成器演进而来:
5.1 初始阶段:生成器只能产出数据
def old_style():
data = yield # 语法支持,但设计上仍是生成器
5.2 增强阶段:通过.send()方法实现双向通信
def enhanced_coroutine():
while True:
received = yield
print(f"收到: {received}")
6. 现代协程(async/await)
Python 3.5+引入了原生协程语法,与生成器彻底分离:
import asyncio
# 原生协程
async def native_coroutine():
await asyncio.sleep(1)
return "完成"
# 生成器协程(已过时)
@asyncio.coroutine
def generator_coroutine():
yield from asyncio.sleep(1)
return "完成"
7. 实际应用场景对比
7.1 生成器的典型应用
# 处理大型文件
def read_large_file(filename):
with open(filename, 'r') as f:
for line in f:
yield line.strip()
# 无限序列
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
7.2 协程的典型应用
import asyncio
# 异步IO操作
async def fetch_data(url):
# 模拟网络请求
await asyncio.sleep(1)
return f"数据来自 {url}"
# 并发任务管理
async def main():
tasks = [
fetch_data("url1"),
fetch_data("url2")
]
results = await asyncio.gather(*tasks)
return results
8. 总结要点
核心区别:
- 生成器:专注于数据的生产,单向通信
- 协程:专注于任务的调度,双向通信
演进路径:
生成器 → 生成器协程 → 原生协程(async/await)
选择标准:
- 需要惰性生成数据序列:使用生成器
- 需要实现并发、异步编程:使用协程
- 需要复杂的任务协调和状态管理:使用协程
理解这个区别有助于在合适的场景选择合适的技术,写出更高效、更易维护的代码。