Python 中with语句详解和代码示例

在 Python 中,with 语句用于简化资源管理(如文件、网络连接、锁等),背后依赖的是上下文管理器协议:即实现了 __enter__()__exit__() 方法的对象。


一、基本概念

with 语句作用:

  • 自动调用资源的初始化(进入上下文)
  • 自动释放资源(即使发生异常)

基本语法:

with expression as variable:
    # 使用资源的代码块
  • expression 是一个返回上下文管理器对象的表达式(必须实现 __enter__()__exit__() 方法)。
  • as variable 是可选的,用于接收 __enter__() 的返回值。

背后的机制:

  • __enter__():当进入 with 代码块时被调用,其返回值赋给 as 后的变量。
  • __exit__(exc_type, exc_val, exc_tb):无论 with 块内是否抛出异常,都会被调用以清理资源。

二、基本示例

示例 1:文件操作(内建实现了上下文管理器)

with open('example.txt', 'r') as f:
    data = f.read()
# 不需要显式 f.close(),异常也会自动处理

等价于:

f = open('example.txt', 'r')
try:
    data = f.read()
finally:
    f.close()

三、自定义上下文管理器(实现 __enter__ / __exit__

示例 2:自定义资源管理类

class MyContext:
    def __enter__(self):
        print("Entering context...")
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        print("Exiting context...")
        if exc_type:
            print(f"Handled exception: {exc_value}")
        return False  # 如果为 True,异常被吞掉;False 表示异常继续传播

# 使用 with
with MyContext() as ctx:
    print("Inside with block")
    # raise ValueError("Something went wrong")  # 可测试异常处理

四、实用场景

示例 3:锁(线程安全)

import threading

lock = threading.Lock()

with lock:
    # 线程安全操作
    pass

示例 4:数据库事务管理(以 SQLAlchemy 为例)

from sqlalchemy.orm import sessionmaker

Session = sessionmaker()
session = Session()

with session.begin():  # 自动提交或回滚
    session.add(some_data)

五、使用 contextlib 快速创建上下文管理器

示例 5:用装饰器实现上下文

from contextlib import contextmanager

@contextmanager
def my_resource():
    print("Acquiring resource")
    yield "resource"
    print("Releasing resource")

with my_resource() as r:
    print(f"Using {r}")

六、实际应用场景综合示例

下是针对 文件操作、GPU 资源管理(如 PyTorch)、日志管理 等实际应用场景的 with 语句和上下文管理器实战示例,每一个都结合了 __enter__ / __exit__ 的机制,适用于高质量的 Python 工程开发。


示例一:文件自动写入上下文管理器

class AutoFileWriter:
    def __init__(self, filename, mode='w'):
        self.filename = filename
        self.mode = mode
        self.file = None

    def __enter__(self):
        print(f"[FileWriter] Opening file: {self.filename}")
        self.file = open(self.filename, self.mode)
        return self.file  # 返回给 with 后的变量

    def __exit__(self, exc_type, exc_value, traceback):
        if self.file:
            print(f"[FileWriter] Closing file: {self.filename}")
            self.file.close()
        if exc_type:
            print(f"[FileWriter] Error: {exc_value}")
        # 返回 False 让异常继续抛出;True 则吞掉异常
        return False

# 使用示例
with AutoFileWriter("output.txt") as f:
    f.write("Hello, file context manager!\n")

️ 示例二:PyTorch GPU 自动切换管理器(多 GPU / CPU fallback)

import torch

class DeviceManager:
    def __init__(self, prefer_cuda=True):
        self.device = torch.device("cuda" if prefer_cuda and torch.cuda.is_available() else "cpu")

    def __enter__(self):
        print(f"[DeviceManager] Using device: {self.device}")
        return self.device  # 返回设备对象

    def __exit__(self, exc_type, exc_value, traceback):
        torch.cuda.empty_cache()  # 清除缓存(可选)
        print(f"[DeviceManager] Released GPU memory.")

# 使用示例
with DeviceManager() as device:
    tensor = torch.randn(1000, 1000).to(device)
    result = tensor @ tensor.T

示例三:日志上下文管理器(自动开始与结束记录)

import logging
from datetime import datetime

class LoggingContext:
    def __init__(self, section_name):
        self.section_name = section_name

    def __enter__(self):
        self.start_time = datetime.now()
        logging.info(f"[{self.section_name}] Start at {self.start_time}")
        return self

    def __exit__(self, exc_type, exc_val, tb):
        end_time = datetime.now()
        logging.info(f"[{self.section_name}] End at {end_time}, Duration: {end_time - self.start_time}")
        if exc_type:
            logging.error(f"[{self.section_name}] Exception: {exc_val}")
        return False

# 配置日志
logging.basicConfig(level=logging.INFO, format="%(message)s")

# 使用
with LoggingContext("Training Step"):
    # 模拟训练
    import time; time.sleep(2)
    logging.info("Model training... complete.")

Bonus:多个上下文组合使用(Python 3.10+ 推荐)

with AutoFileWriter("log.txt") as f, DeviceManager() as device:
    f.write(f"Computation on device: {device}\n")
    t = torch.ones(2, 2).to(device)
    f.write(f"Tensor:\n{t}\n")

示例总结说明

场景管理器类名资源自动化操作
文件AutoFileWriter文件句柄自动打开 / 关闭文件
GPUDeviceManagertorch.device自动设备分配 / 清理 CUDA 缓存
日志记录LoggingContext日志上下文自动打印开始、结束、异常

7、总结

方法说明
__enter__()初始化资源,返回给 as 变量
__exit__()清理资源,处理异常(3 个参数)
contextlib提供装饰器方式快速创建上下文管理器

使用 with 的好处

优点描述
自动资源释放无需手动 close()、release() 等
异常安全发生异常时也能执行清理代码
代码更简洁避免冗长的 try/finally 结构
可扩展可以自定义任意资源管理器

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

点云SLAM

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值