2023.11.2 “@contextmanager”装饰器: Python 中的上下文管理器
@contextmanager 装饰器是 Python 中的一个装饰器,它用于将一个生成器函数转换为上下文管理器。生成器函数定义了一个带有 yield 语句的函数,当函数被调用时,它会返回一个生成器对象。生成器可以通过多次调用 next() 函数来逐个返回值,每次调用 yield 语句后会暂停函数执行,等待下一次调用。
使用 @contextmanager 装饰器可以更方便地创建上下文管理器,避免手动编写 enter() 和 exit() 方法。
当使用上下文管理器对象的 with 语句时,Python 会调用这个上下文管理器对象的 enter() 方法,在进入 with 代码块之前执行一些准备工作。当 with 代码块执行完成后,Python 会调用这个上下文管理器对象的 exit() 方法,在退出 with 代码块时进行一些清理工作。
下面是一个示例,展示如何使用 @contextmanager 装饰器创建一个上下文管理器:
from contextlib import contextmanager
@contextmanager
def my_context_manager():
# 进入上下文前的准备工作
print("Enter context.")
try:
# 返回一个值,这个值可以在 with 语句块中使用
yield "Hello, world!"
finally:
# 退出上下文后的清理工作
print("Exit context.")
# 使用上下文管理器
with my_context_manager() as msg:
print(msg)
输出结果如下:
使用 @contextmanager 装饰器可以简化创建上下文管理器的过程,避免手动编写 enter() 和 exit() 方法。可以提高代码的可读性和可维护性。
当不使用 @contextmanager 装饰器时,可以手动编写实现上下文管理器的代码,可以使用 try-finally 结构来确保资源的正确释放。下面是一个示例:
class MyContextManager:
def __enter__(self):
# 进入上下文前的准备工作
print("Enter context.")
# 返回一个值,这个值可以在 with 语句块中使用
return "Hello, world!"
def __exit__(self, exc_type, exc_value, traceback):
# 退出上下文后的清理工作
print("Exit context.")
# 使用上下文管理器
try:
cm = MyContextManager()
msg = cm.__enter__()
print(msg)
finally:
cm.__exit__(None, None, None) # 清理资源
输出结果如下(和之前使用 @contextmanager的输出结果相同):
使用 @contextmanager 装饰器操作数据库比较方便,可以确保每次调用数据库的正常连接和关闭。
from contextlib import contextmanager
import pymysql
@contextmanager
def database_connection():
conn = pymysql.connect(host='域名', user='用户名', password='密码', db='数据库名')
try:
yield conn
finally:
conn.close()
# 在代码中使用上下文管理器
with database_connection() as conn:
with conn.cursor() as cursor:
# 执行数据库操作
cursor.execute(sql, params)