Python yield 的正确使用

定义上下文管理器

python 复制代码
import contextlib

@contextlib.contextmanager
def open_managed_file(filepath, mode='r'):
    """
    一个上下文管理器,用于安全地打开和关闭文件。
    """
    f = None
    try:
        # 1. 资源获取/进入上下文 (__enter__)
        f = open(filepath, mode)
        print(f"[ENTER]: 成功打开文件 '{filepath}',模式为 '{mode}'")
        
        # 2. 暂停并返回资源
        # yield 后面的值 (f) 将被绑定到 with ... as 后的变量上
        yield f 

    except FileNotFoundError:
        print(f"[EXIT]: 错误!文件 '{filepath}' 未找到。")
        raise
        
    finally:
        # 3. 资源清理/退出上下文 (__exit__)
        if f:
            print(f"[EXIT]: 正在关闭文件 '{filepath}'...")
            f.close()

使用 with 语句进行文件操作

我们首先创建一个临时文件供读取,然后使用上下文管理器。

python 复制代码
# 1. 创建一个测试文件
TEST_FILE = "test_config.txt"
with open(TEST_FILE, "w") as temp:
    temp.write("Setting A=10\n")
    temp.write("Setting B=20\n")

print("-" * 30)

# 2. 使用上下文管理器读取文件
try:
    with open_managed_file(TEST_FILE, 'r') as file_handle:
        # 在 with 块内,file_handle 就是 open_managed_file 中 yield 返回的文件对象
        content = file_handle.read()
        print("\n[WITH BLOCK]: 文件内容读取完成。")
        print("---")
        print(content.strip())
        print("---")

    # 当 with 块结束时,文件已被自动关闭 (执行了 finally 块)
    print("上下文管理块正常退出。")

except FileNotFoundError:
    print("程序捕获到文件未找到的错误。")

运行结果(会显示整个流程):

yaml 复制代码
------------------------------
[ENTER]: 成功打开文件 'test_config.txt',模式为 'r'

[WITH BLOCK]: 文件内容读取完成。
---
Setting A=10
Setting B=20
---
[EXIT]: 正在关闭文件 'test_config.txt'...
上下文管理块正常退出。

异常处理演示

即使在 with 块内部发生异常,finally 块也会确保文件被关闭:

python 复制代码
print("-" * 30)
print("演示异常情况下的清理:")

try:
    with open_managed_file(TEST_FILE, 'r') as file_handle:
        print("[WITH BLOCK]: 尝试读取文件...")
        
        # 故意制造一个错误(例如,除以零)
        result = 10 / 0 
        print(f"这个不会被打印: {result}")
        
except ZeroDivisionError:
    # 外部捕获了异常,但文件已经在退出时关闭了
    print("\n[外部]: 成功捕获到 ZeroDivisionError。")
    # 注意,即使发生了异常,open_managed_file 内部的 finally 块也会先执行。

异常运行结果(显示清理优先于异常捕获):

markdown 复制代码
------------------------------
演示异常情况下的清理:
[ENTER]: 成功打开文件 'test_config.txt',模式为 'r'
[WITH BLOCK]: 尝试读取文件...
[EXIT]: 正在关闭文件 'test_config.txt'...

[外部]: 成功捕获到 ZeroDivisionError。

通过这种方式,我们使用了一个简洁的生成器函数 (open_managed_file),结合 @contextlib.contextmanagertry...finally 结构,优雅且安全地实现了上下文管理。

相关推荐
Java后端的Ai之路3 小时前
【Python 教程15】-Python和Web
python
冬奇Lab4 小时前
一天一个开源项目(第15篇):MapToPoster - 用代码将城市地图转换为精美的海报设计
python·开源
二十雨辰6 小时前
[python]-AI大模型
开发语言·人工智能·python
Yvonne爱编码6 小时前
JAVA数据结构 DAY6-栈和队列
java·开发语言·数据结构·python
前端摸鱼匠7 小时前
YOLOv8 环境配置全攻略:Python、PyTorch 与 CUDA 的和谐共生
人工智能·pytorch·python·yolo·目标检测
WangYaolove13147 小时前
基于python的在线水果销售系统(源码+文档)
python·mysql·django·毕业设计·源码
AALoveTouch8 小时前
大麦网协议分析
javascript·python
ZH15455891318 小时前
Flutter for OpenHarmony Python学习助手实战:自动化脚本开发的实现
python·学习·flutter
xcLeigh8 小时前
Python入门:Python3 requests模块全面学习教程
开发语言·python·学习·模块·python3·requests
xcLeigh8 小时前
Python入门:Python3 statistics模块全面学习教程
开发语言·python·学习·模块·python3·statistics