Menu
CoddyTech

上下文管理器

本课属于 Coddy Python 学习旅程的“面向对象编程”单元。第 41 课,共 64 课。

上下文管理器可以让你在需要时准确地分配和释放资源。即使发生错误,它们也能确保正确清理资源。

下面是使用 with 语句的最常见示例:

with open('example.txt', 'w') as file:
    file.write('Hello, world!')
# 文件会在这里自动关闭

即使发生异常,代码块结束后文件也会自动关闭。

通过实现 __enter__ 和 __exit__ 方法来创建自己的上下文管理器:

class MyContext:
    def __enter__(self):
        print("Entering the context")
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("Exiting the context")
        return False  # 不要忽略异常

使用你自定义的上下文管理器:

with MyContext() as ctx:
    print("Inside the context")

输出:

Entering the context
Inside the context
Exiting the context

为数据库连接创建一个更实用的上下文管理器:

class DatabaseConnection:
    def __init__(self, db_name):
        self.db_name = db_name
        self.connection = None
    
    def __enter__(self):
        print(f"Connecting to {self.db_name}")
        self.connection = f"Connection to {self.db_name}"
        return self.connection
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print(f"Closing connection to {self.db_name}")
        self.connection = None

with DatabaseConnection("users_db") as conn:
    print(f"Using {conn}")
    print("Performing database operations...")

在上下文管理器中处理异常:

class SafeContext:
    def __enter__(self):
        print("Setting up resources")
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("Cleaning up resources")
        if exc_type:
            print(f"An exception occurred: {exc_val}")
        return False  # 不要抑制异常

with SafeContext():
    print("Working with resources")
    # raise ValueError("Something went wrong")  # 取消注释以进行测试

输出:

Connecting to users_db
Using Connection to users_db
Performing database operations...
Closing connection to users_db
Setting up resources
Working with resources
Cleaning up resources

__exit__ 方法会接收三个参数:

  • exc_type:异常类型(或 None)
  • exc_val:异常值(或 None)
  • exc_tb:异常回溯信息(或 None)

要点:上下文管理器使用 __enter__ 和 __exit__ 方法来管理资源。with 语句会自动调用这些方法,确保正确地进行设置和清理。这对于文件、数据库连接以及其他需要确保清理的资源尤其有用。

challenge icon

挑战

简单

在这个挑战中,你将实现一个上下文管理器类,用于测量进入和退出上下文块之间经过的时间。

  • timer.py:包含 Timer 类的实现(你要编辑这个文件)
  • driver.py:包含全面的测试用例(不要修改)

按照 TODO 注释,在 timer.py 中实现 Timer 上下文管理器。这个类应该:

  1. 进入上下文时记录开始时间
  2. 退出上下文时记录结束时间
  3. 计算并显示经过的时间

亲手试试

from timer import Timer
import time

# 测试用例处理程序
test_case = input()

if test_case == "basic_test":
    # 基本功能测试
    with Timer():
        # 模拟一些工作
        time.sleep(2)  # 这会让程序等待 2 秒

elif test_case == "nested_contexts":
    # 测试嵌套的上下文管理器
    with Timer():
        time.sleep(1)
        with Timer():
            time.sleep(1)

elif test_case == "exception_handling":
    # 测试上下文中的异常处理
    try:
        with Timer():
            time.sleep(1)
            raise ValueError("Test exception")
    except ValueError as e:
        print(f"Caught exception: {e}")

elif test_case == "zero_sleep":
    # 测试极短的休眠时间
    with Timer():
        time.sleep(0.001)

elif test_case == "multiple_timers":
    # 测试依次使用多个计时器
    with Timer():
        time.sleep(1)
    
    with Timer():
        time.sleep(0.5)
    
    with Timer():
        time.sleep(2)

elif test_case == "as_decorator":
    # 测试在函数中使用计时器
    def timed_function():
        with Timer():
            time.sleep(2)
    
    timed_function()

else:
    # 默认测试:基本功能
    with Timer():
        # 模拟一些工作
        time.sleep(2)  # 这会让程序等待 2 秒
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Python 在线编译器