Python yield 语法认识, yield的使用方法

yield在这里确实是一个关键语法,它标志着上下文管理器的“执行分界线”。下面我用具体例子来详细解释。
yield的核心作用:执行分界线
简单来说,yield语句将你的上下文管理器函数(被 @contextmanager装饰的函数)分成了三个部分:
yield之前的代码:相当于上下文管理器的__enter__方法。在进入with语句块之前执行,通常负责准备工作,比如获取资源、记录初始状态。在你的代码中,就是start = time.perf_counter()。yield语句本身:它是一个暂停点。程序执行到这里会暂停,并将yield后面的值(如果有)返回给with语句中as关键字指定的变量。在你的代码中,yield后面没有值,所以不返回资源,只是暂停。yield之后的代码:相当于上下文管理器的__exit__方法。在退出with语句块之后执行,无论块内的代码是正常结束还是发生异常都会执行(这得益于try...finally结构)。通常负责清理工作,比如释放资源、记录结束状态。在你的代码中,就是计算并打印耗时。
整个执行流程,以及 yield如何作为分界线,可以用下表清晰地展示:
扩展示例:让 yield传递资源
yield的一个强大之处在于它可以向 with代码块内传递一个资源或对象,并在块内代码执行完毕后确保该资源被正确清理。下面看几个具体的例子。
1. 自动管理文件操作状态
这个例子模拟一个数据处理任务,yield传递一个状态字典,用于在 with块内外记录信息。
from contextlib import contextmanager
import time
@contextmanager
def managed_data_processor(operation_name):
# 进入with块前:准备工作 (相当于 __enter__)
start_time = time.perf_counter()
status = {"operation": operation_name, "start_time": start_time, "success": False}
print(f"[{operation_name}] 开始处理...")
try:
# yield 传递status字典到with块内,并暂停执行
yield status
# 如果with块内代码正常执行完毕,回到这里,标记成功
status["success"] = True
except Exception as e:
# 如果with块内发生异常,也会回到这里
status["error"] = str(e)
print(f"[{operation_name}] 处理出错: {e}")
# 异常会被继续抛出,除非这里return True
raise
finally:
# 退出with块后:清理工作 (相当于 __exit__)
end_time = time.perf_counter()
duration = end_time - start_time
status["end_time"] = end_time
status["duration"] = duration
if status.get("success"):
print(f"[{operation_name}] 处理成功!耗时: {duration:.4f}秒")
else:
print(f"[{operation_name}] 处理失败!耗时: {duration:.4f}秒")
# 使用示例
with managed_data_processor("数据导入") as proc_status:
# 这里可以操作yield传出的status字典
proc_status["rows_processed"] = 1000
# 模拟一个耗时操作
time.sleep(0.5)
# 可以取消下一行的注释来模拟异常情况
# raise ValueError("模拟一个错误")输出(正常情况):
[数据导入] 开始处理...
[数据导入] 处理成功!耗时: 0.5001秒输出(有异常时):
[数据导入] 开始处理...
[数据导入] 处理出错: 模拟一个错误
[数据导入] 处理失败!耗时: 0.0002秒
Traceback (most recent call last):
...2. 临时切换工作目录(并确保切回)
这个例子展示了如何使用 yield管理一个“状态”而不是一个具体的“资源”,并在最后确保状态恢复。
from contextlib import contextmanager
import os
@contextmanager
def temporary_cd(new_dir):
# 进入with块前:保存当前目录
original_dir = os.getcwd()
os.chdir(new_dir)
print(f"已切换到目录: {os.getcwd()}")
try:
# yield 之前已切换目录,此处不传递值,只是暂停
yield
# with块内代码执行完毕后,会回到这里
finally:
# 退出with块后:无论是否异常,都切回原目录
os.chdir(original_dir)
print(f"已切换回目录: {os.getcwd()}")
# 使用示例
print(f"起始目录: {os.getcwd()}")
with temporary_cd("/tmp"): # 假设/tmp目录存在
# 在这个块内,当前工作目录是 /tmp
print(f"块内当前目录: {os.getcwd()}")
# 可以在这里进行一些只在/tmp目录下的操作,比如创建临时文件
with open("tempfile.txt", "w") as f:
f.write("hello")
# 退出with块后,目录自动切回起始目录
print(f"结束目录: {os.getcwd()}")总结
yield是一个关键词:它是 Python 中用于定义生成器或(配合@contextmanager)创建上下文管理器的核心语法。yield是指一个“操作节点”:它代表了执行流程的暂停和恢复点,将代码逻辑清晰地划分为“进入时准备”、“内部执行”和“退出时清理”三个阶段。yield可以传递数据:通过yield resource,你可以将资源(如文件对象、数据库连接、状态字典)安全地传递给with块内的代码使用,并保证后续的清理工作。
这种模式极大地简化了资源管理代码,使其更安全、更清晰、更符合 Python 的优雅风格。
更多文章:
python with的原理,python with 在django框架当中有哪些优秀用法
2025年11月4日 11:15
Python操作数据库方法总结,Python如何高效的进行数据库交互
2025年11月3日 23:23



















