跳转至

上下文管理器

上下文管理器是 Python 中用于管理资源的机制,确保资源在使用后被正确释放,例如自动关闭文件或释放锁。

with 语句

1
2
3
with open("file.txt", "w") as f:
    f.write("Hello")
# 文件自动关闭
  • 适用场景:适用于需要管理资源(如文件、数据库连接、锁)的场景,确保资源不会泄漏。

实现上下文管理器

基于类

class Timer:
    def __enter__(self):
        import time
        self.start = time.time()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.end = time.time()
        print(f"耗时: {self.end - self.start:.2f}s")

with Timer() as t:
    import time
    time.sleep(1)
  • 解释__enter__ 是进入上下文时调用的方法,__exit__ 是退出时调用的方法。
  • 适用场景:适用于需要测量代码执行时间的场景。

基于生成器

from contextlib import contextmanager

@contextmanager
def tag(name):
    print(f"<{name}>", end="")
    yield
    print(f"</{name}>")

with tag("h1"):
    print("标题", end="")
# 输出: <h1>标题</h1>
  • 解释@contextmanager 是一个装饰器,可以把生成器函数变成上下文管理器,超级方便!
  • 适用场景:适用于需要临时设置和清理资源的场景,比如 HTML 标签的生成~

内置上下文管理器

Python 还自带了一些超好用的内置上下文管理器,比如 openthreading.Lock,它们都会帮你自动管理资源,再也不用担心忘记释放啦!

# 临时重定向标准输出
from contextlib import redirect_stdout
with redirect_stdout(open("output.txt", "w")):
    print("Hello")

# 临时修改目录
from contextlib import chdir
with chdir("/tmp"):
    import os
    print(os.getcwd())

实践练习

练习1:数据库连接

class DatabaseConnection:
    def __enter__(self):
        print("连接数据库")
        return self

    def __exit__(self, *args):
        print("关闭数据库")

    def query(self, sql):
        print(f"执行: {sql}")

# with DatabaseConnection() as db:
#     db.query("SELECT * FROM users")

练习2:锁机制

import threading

class LockContext:
    def __enter__(self):
        self.lock = threading.Lock()
        self.lock.acquire()
        print("获取锁")
        return self

    def __exit__(self, *args):
        self.lock.release()
        print("释放锁")

# with LockContext():
#     print("临界区代码")

小结

上下文管理器简化了资源管理,确保资源正确释放。