ZetCode

Python __enter__ 方法

最后修改于 2025 年 4 月 8 日

本综合指南探讨了 Python 的 __enter__ 方法,这是在上下文管理器中使用的特殊方法。我们将介绍基本用法、资源管理、文件处理、数据库连接和实际示例。

基本定义

__enter__ 方法是 Python 上下文管理器协议的一部分。它定义了在 with 语句块开始时发生的事情。

主要特点:它在进入运行时上下文时被调用,返回一个绑定到 as 变量的对象,并与 __exit__ 协同工作以进行干净的资源管理。它启用了 "with" 语句功能。

基本上下文管理器

这是一个简单的上下文管理器,演示了 __enter____exit__ 协同工作以管理资源。

basic_context.py
class SimpleContext:
    def __enter__(self):
        print("Entering context")
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("Exiting context")
    
    def show(self):
        print("Inside context")

with SimpleContext() as ctx:
    ctx.show()

此示例显示了上下文管理器的基本结构。进入 with 块时调用 __enter__,离开时调用 __exit__。输出显示了执行顺序。

__enter__ 方法返回 self,它被分配给 ctx。这允许在上下文管理器对象上调用方法。

文件处理上下文管理器

__enter__ 的常见用途是在文件处理中,它确保正确的文件打开和关闭。

file_context.py
class FileHandler:
    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode
    
    def __enter__(self):
        self.file = open(self.filename, self.mode)
        return self.file
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.file.close()

with FileHandler('example.txt', 'w') as f:
    f.write('Hello, context manager!')

这个自定义文件处理程序模仿了 Python 的内置文件上下文管理器。 __enter__ 打开文件并返回文件对象。

即使发生异常,__exit__ 方法也会确保文件关闭。这可以防止资源泄漏并处理清理。

数据库连接上下文管理器

__enter__ 非常适合管理数据库连接,确保在使用后正确关闭它们。

db_context.py
import sqlite3

class DatabaseConnection:
    def __init__(self, db_name):
        self.db_name = db_name
    
    def __enter__(self):
        self.conn = sqlite3.connect(self.db_name)
        return self.conn
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.conn.close()
        if exc_type is not None:
            print(f"Error occurred: {exc_val}")

with DatabaseConnection('test.db') as conn:
    cursor = conn.cursor()
    cursor.execute("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)")

此上下文管理器处理 SQLite 数据库连接。 __enter__ 建立连接并返回它以在 with 块中使用。

__exit__ 关闭连接并可选择处理异常。这种模式确保数据库资源被正确释放。

计时上下文管理器

通过在进入上下文时记录开始时间,可以使用 __enter__ 来测量执行时间。

timer_context.py
import time

class Timer:
    def __enter__(self):
        self.start = time.time()
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.end = time.time()
        print(f"Elapsed time: {self.end - self.start:.2f} seconds")

with Timer():
    time.sleep(1)
    sum(range(1000000))

此计时器上下文管理器在 __enter__ 中记录开始时间,并在 __exit__ 中计算经过的时间。它演示了一个非资源用例。

在这种情况下,上下文管理器不需要返回有用的对象,因此它只返回 self。计时逻辑完全在 enter/exit 中。

具有状态的上下文管理器

__enter__ 可以管理复杂的状态设置和拆卸,如本临时目录示例所示。

tempdir_context.py
import os
import tempfile
import shutil

class TemporaryDirectory:
    def __enter__(self):
        self.dirname = tempfile.mkdtemp()
        return self.dirname
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        shutil.rmtree(self.dirname)

with TemporaryDirectory() as tempdir:
    print(f"Created temp directory: {tempdir}")
    with open(os.path.join(tempdir, 'test.txt'), 'w') as f:
        f.write('Temporary file content')

此上下文管理器在 __enter__ 中创建一个临时目录并返回其路径。 __exit__ 通过删除目录来清理。

该示例展示了 __enter__ 如何处理复杂的设置操作,同时确保正确的清理,即使在执行过程中发生异常。

最佳实践

资料来源

作者

我叫 Jan Bodnar,是一位充满热情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直在撰写编程文章。到目前为止,我已经撰写了超过 1,400 篇文章和 8 本电子书。我拥有超过十年的编程教学经验。

列出所有 Python 教程