想象你正在观看一部可以随时暂停的科幻电影:
def time_machine():
yield "回到1920年"
yield "穿越到2050年"
yield "抵达恐龙时代"
traveler = time_machine()
print(next(traveler)) # 回到1920年
print(next(traveler)) # 穿越到2050年
这不是普通的函数,而是一台可以随时暂停的时间机器。今天我们将揭开Python最迷人的特性——生成器与协程的神秘面纱。
普通函数像自动售货机(投币→出货),生成器像咖啡师(边做边交流):
# 传统函数
def make_coffee():
return "☕"
# 生成器函数
def barista():
yield "磨豆"
yield "萃取"
yield "拉花"
yield "☕"
order = barista()
print(next(order)) # 磨豆
print(next(order)) # 萃取
生成器三大特征:
用yield
替代return
执行到yield时冻结现场
通过__next__()
唤醒执行
对比两种实现方式处理1000万数据:
# 普通列表(立即加载)
def load_all():
return [i**2 for i in range(10_000_000)] # 瞬间吃掉400MB内存
# 生成器(按需生产)
def stream_data():
for i in range(10_000_000):
yield i**2 # 始终只占几十字节
内存占用实测对比:
方式 | 内存峰值 | 启动速度 | 适用场景 |
---|---|---|---|
列表 | 400MB | 慢 | 小数据集即时处理 |
生成器 | 50KB | 即时 | 大数据流处理 |
用.send()
方法实现双向通信:
def smart_thermostat():
current_temp = 25
while True:
new_temp = yield current_temp
if new_temp is not None:
current_temp = new_temp
ac = smart_thermostat()
next(ac) # 启动协程
print(ac.send(20)) # 20
print(ac.send(None)) # 保持20
协程进化史:
Python 2.5: 基本协程
Python 3.3: yield from
Python 3.5: async/await
两种写法看似相同,实则天差地别:
# 列表推导式(立即生成)
big_list = [x*2 for x in range(10**6)] # 占用8MB内存
# 生成器表达式(惰性计算)
gen_expr = (x*2 for x in range(10**6)) # 内存几乎为0
# 管道式处理
pipeline = (x**2 for x in gen_expr if x%3 ==0)
性能对比测试(处理1GB数据):
import time
# 传统方式
start = time.time()
[x**2 for x in range(10**7) if x%2 ==0]
print(f"列表耗时: {time.time()-start:.2f}s")
# 生成器方式
start = time.time()
sum(x**2 for x in range(10**7) if x%2 ==0)
print(f"生成器耗时: {time.time()-start:.2f}s")
典型结果:
列表方式:3.21秒(内存爆满)
生成器方式:2.87秒(内存平稳)
大文件流式处理:
def read_giant_file(path):
with open(path, 'r') as f:
while chunk := f.read(4096):
yield chunk
# 处理10GB文件只需40MB内存
for block in read_giant_file("huge.log"):
process(block)
无限序列生成:
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
# 获取前100个斐波那契数
print([x for _,x in zip(range(100), fibonacci())])
状态机实现:
def traffic_light():
states = ["", "", ""]
index = 0
while True:
yield states[index]
index = (index + 1) % 3
yield states[index]
index = (index + 1) % 3
# 交替闪烁黄灯
light = traffic_light()
print(next(light)) #
print(next(light)) #
print(next(light)) #
print(next(light)) #
当你理解生成器的本质后,会看到Python代码中处处流淌着时间的长河。每个yield都是一个时间锚点,协程是跨越时空的对话,而async/await则是操控时间的终极咒语。