Python - 上下文管理器



Python 中的上下文管理器提供了一种高效、安全地管理资源的强大方法。Python 中的上下文管理器是一个对象,它定义用于 with 语句的运行时上下文。它确保自动执行设置和清理操作。

例如,在处理文件操作时,上下文管理器会处理文件的打开和关闭,从而确保资源得到正确管理。

上下文管理器如何工作?

Python 上下文管理器通过实现 __enter__() __exit__() 方法(或它们用于异步操作的异步等效方法)来工作。这些方法可以确保正确获取和释放资源。此外,Python 的 contextlib 模块进一步简化了自定义上下文管理器的创建。

这是一个简单的示例,演示了上下文管理器如何处理 Python 中的文件操作。


with open('example.txt', 'w') as file:
	 	 file.write('Hello, qikepu!')

在此示例中,文件以写入模式打开,然后在退出 with 语句内的块时自动关闭。

Python 上下文管理器类型

Python 支持同步和异步上下文管理器。每种类型都有特定的方法,需要实现这些方法来管理上下文的生命周期。

同步上下文管理器

A 同步上下文管理器是使用 __enter__() __exit__() 方法实现的。

1. __enter__() 方法

当执行进入 with 语句的上下文时,将调用 __enter__(self) 方法。此方法应返回要在 with 块中使用的资源。

这是一个使用 __enter__() __exit__() 方法创建我们自己的上下文管理器的简单示例。


class MyContextManager:
	 	def __enter__(self):
	 	 	 print("Entering the context")
	 	 	 return self

	 	def __exit__(self, exc_type, exc_value, traceback):
	 	 	 print("Exiting the context")
	 	 	 		
with MyContextManager():
	 	print("body")

在执行上述代码时,您将获得以下输出 -

Entering the context
body
Exiting the context

2. __exit__() 方法

当执行离开 with 语句的上下文时,将调用 __exit__(self, exc_type, exc_value, traceback) 方法。如果发生异常,它可以处理异常,并返回一个布尔标志,指示是否应禁止显示异常。

这个例子演示了如何创建我们自己的上下文管理器,以及 __exit__() 方法如何处理异常。


class MyContextManager:
	 	def __enter__(self):
	 	 	 print("Entering the context")
	 	 	 return self

	 	def __exit__(self, exc_type, exc_value, traceback):
	 	 	 print("Exiting the context")
	 	 	 if exc_type:
	 	 	 	 	print("An exception occurred")
	 	 	 return True 	# Suppress exception

with MyContextManager():
	 	print("body")
	 	name = 	"Python"/3 #to raise an exception

在执行上述代码时,您将获得以下输出 -

Entering the context
body
Exiting the context
An exception occurred

异步上下文管理器

与同步上下文管理器类似,异步上下文管理器也使用 __aenter__() __aexit__() 两种方法实现。这些在 async with 语句中使用。

  • __aenter__(self) 方法 − 它必须返回一个 awaitable,该 awaitable 将在进入上下文时被 await。
  • __aexit__(self, exc_type, exc_value, traceback) 方法 − 它必须返回一个在退出上下文时将等待的 awaitable。

以下是创建异步上下文管理器类的示例 -


import asyncio
class AsyncContextManager:
	 	async def __aenter__(self):
	 	 	 print("Entering the async context class")
	 	 	 return self

	 	async def __aexit__(self, exc_type, exc_value, traceback):
	 	 	 print("Exiting the async context class")
	 	 	 if exc_type:
	 	 	 	 	print("Exception occurred")
	 	 	 return True

async def main():
	 	async with AsyncContextManager():
	 	 	 print("Inside the async context")
	 	 	 name = 	"Python"/3 #to raise an exception

asyncio.run(main())

在执行上述代码时,您将获得以下输出 -

Entering the async context class
Inside the async context
Exiting the async context class
Exception occurred

创建自定义上下文管理器

Python 标准库中的 contextlib 模块提供了可以更轻松地创建上下文管理器的实用程序。

使用 contextlib.contextmanager() 函数

contextlib.contextmanager() 函数是一个装饰器,允许您为语句上下文管理器创建工厂函数。它消除了定义单独类或单独实现 __enter__() __exit__() 方法的需要。

这是一个使用 contextlib.contextmanager 创建上下文管理器函数的示例。


from contextlib import contextmanager

@contextmanager
def my_context_manager():
	 	print("Entering the context manager method")
	 	try:
	 	 	 yield
	 	finally:
	 	 	 print("Exiting the context manager method")

with my_context_manager():
	 	print("Inside the context")

在执行上述代码时,您将获得以下输出 -

Entering the context manager method
Inside the context
Exiting the context manager method

使用 contextlib.asynccontextmanager() 函数

contextlib 模块还提供了 asynccontextmanager,专门用于创建异步上下文管理器。它类似于 contextmanager,无需定义单独的类或单独实现 __aenter__() __aexit__() 方法。

这是一个示例,演示了如何使用 contextlib.asynccontextmanager() 创建异步上下文管理器函数。


import asyncio
from contextlib import asynccontextmanager

@asynccontextmanager
async def async_context_manager():
	 	try:
	 	 	 print("Entering the async context")
	 	 	 # Perform async setup tasks if needed
	 	 	 yield
	 	finally:
	 	 	 # Perform async cleanup tasks if needed
	 	 	 print("Exiting the async context")

async def main():
	 	async with async_context_manager(): 	
	 	 	 print("Inside the async context")
	 	 	 await asyncio.sleep(1) 	# Simulating an async operation

# Run the asyncio event loop
asyncio.run(main())

在执行上述代码时,您将获得以下输出 -

Entering the async context
Inside the async context
Exiting the async context