当前位置:首页>python>【一起学Python】第19天:with 关键字

【一起学Python】第19天:with 关键字

  • 2026-09-02 20:22:40
【一起学Python】第19天:with 关键字
with 关键字为 Python 开发者提供了一种优雅且高效的资源管理机制,它通过上下文管理协议(Context Management Protocol)确保资源在使用完毕后能够被正确地获取和释放,从而避免了资源泄漏和程序崩溃的风险。

传统资源管理的问题

在 with 语句出现之前,Python 中处理需要释放的资源通常依赖于 try...finally 结构。以下是一个典型的文件操作示例:

file = open('example.txt', 'r')try:    content = file.read()    # 处理文件内容finally:    file.close()

这种传统方法存在以下几个显著问题:

容易忘记关闭资源:如果开发者忘记在 finally 块中调用 close() 方法,资源将无法被释放,可能导致文件句柄泄露、内存占用过高或数据损坏等问题。

一、什么是 with 关键字?

with 语句用于创建一个“上下文管理器”,它会在代码块执行前后自动调用特定方法,完成资源的初始化和清理工作。

基本语法:

with 表达式 as 变量:    # 使用资源的代码块

二、为什么使用 with?

❌ 不使用 with 的写法:

f = open('file.txt', 'r')try:    content = f.read()finally:    f.close()

✅ 使用 with 的写法:

withopen('file.txt', 'r') as f:    content = f.read()# 自动关闭文件,即使发生异常

优势:

  • 自动资源释放(如关闭文件、断开连接)
  • 异常安全,确保清理代码始终执行
  • 代码更简洁、可读性更高

三、常见使用场景

1. 文件操作

# 读取文件with open('data.txt', 'r', encoding='utf-8') as f:    content = f.read()# 写入文件with open('output.txt', 'w', encoding='utf-8') as f:    f.write('Hello, Python!')# 同时读写多个文件with open('input.txt', 'r') as infile, open('output.txt', 'w') as outfile:    outfile.write(infile.read())

2. 数据库连接

import sqlite3with sqlite3.connect('database.db') as conn:    cursor = conn.cursor()    cursor.execute('SELECT * FROM users')    results = cursor.fetchall()# 自动提交或回滚事务,关闭连接

3. 线程锁

from threading import Locklock = Lock()with lock:    # 临界区代码,自动加锁和解锁    pass

4. 临时更改配置

import osoriginal_dir = os.getcwd()with open('temp.txt', 'w'):    pass  # 创建临时文件# 使用 contextlib 更优雅from contextlib import contextmanager@contextmanagerdef change_dir(path):    old_dir = os.getcwd()    os.chdir(path)    try:        yield    finally:        os.chdir(old_dir)with change_dir('/tmp'):    # 临时切换目录    pass

四、自定义上下文管理器

方法一:使用类实现

class FileManager:    def __init__(self, filename, mode):        self.filename = filename        self.mode = mode        self.file = None    def __enter__(self):        self.file = open(self.filename, self.mode)        return self.file    def __exit__(self, exc_type, exc_val, exc_tb):        if self.file:            self.file.close()        return False  # 不抑制异常# 使用with FileManager('test.txt', 'w') as f:    f.write('Hello')

方法二:使用 contextlib.contextmanager 装饰器

from contextlib import contextmanager@contextmanagerdef file_manager(filename, mode):    f = open(filename, mode)    try:        yield f    finally:        f.close()# 使用with file_manager('test.txt', 'w') as f:    f.write('Hello')

五、多个 with 语句

Python 3.10+ 支持括号写法:

with (    open('file1.txt', 'r') as f1,    open('file2.txt', 'w') as f2):    f2.write(f1.read())

旧版本写法:

with open('file1.txt', 'r') as f1, open('file2.txt', 'w') as f2:    f2.write(f1.read())

六、exit 方法参数说明

def __exit__(self, exc_type, exc_val, exc_tb):    # exc_type: 异常类型    # exc_val: 异常值    # exc_tb: 异常追踪信息    # 返回 True 可抑制异常,False 则继续传播

示例:捕获并处理异常

class SafeFile:    def __init__(self, filename):        self.filename = filename    def __enter__(self):        self.file = open(self.filename, 'r')        return self.file    def __exit__(self, exc_type, exc_val, exc_tb):        self.file.close()        if exc_type is FileNotFoundError:            print(f"文件 {self.filename} 不存在")            return True  # 抑制异常        return False

七、最佳实践与注意事项

✅ 推荐做法:

  • 所有需要手动关闭的资源都应使用 with
  • 自定义上下文管理器时确保 __exit__ 中清理资源
  • 使用 contextlib 简化自定义管理器

❌ 避免做法:

  • 在 with 块外部使用资源变量(可能已关闭)
  • 在 __exit__ 中忽略异常处理逻辑
  • 滥用 with 于无需清理的资源

示例:错误用法

with open('file.txt', 'r') as f:    content = f.read()print(f.read())  # ❌ 文件已关闭,会报错

八、实战示例

1. 计时器上下文管理器

import timefrom contextlib import contextmanager@contextmanagerdef timer(name="操作"):    start = time.time()    try:        yield    finally:        end = time.time()        print(f"{name} 耗时: {end - start:.4f} 秒")with timer("数据处理"):    time.sleep(1)

2. 数据库事务管理

from contextlib import contextmanagerimport sqlite3@contextmanagerdef db_transaction(db_name):    conn = sqlite3.connect(db_name)    try:        yield conn        conn.commit()    except:        conn.rollback()        raise    finally:        conn.close()with db_transaction('mydb.db') as conn:    cursor = conn.cursor()    cursor.execute('INSERT INTO users (name) VALUES (?)', ('Alice',))

九、总结

with 是 Python 中实现资源安全管理的最佳实践,建议在所有涉及资源操作的场景中优先使用。

最新文章

随机文章