Python 简明教程

Python - Context Managers

Context managers 在 Python 中提供了一种有效管理资源安全性的强有力方式。Python 中的 context manager 是一个对象,它为 with 语句的使用定义了一个运行时上下文。它确保自动执行设置和清除操作。

例如,当处理文件操作时,上下文管理器处理文件的打开和关闭,确保正确管理资源。

How Context Managers Work?

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

Example

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

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

在此示例中,已在写模式下打开一个文件,当 with 语句内的块被退出时自动关闭。

Python Context Manager Types

Python 支持同步和异步上下文管理器。每种类型都有用于管理上下文生命周期的特定方法。

Synchronous Context Managers

同步上下文管理器使用 enter()exit() 方法实现。

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

Example

下面是一个使用 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")

执行上述代码后,您将获得以下 output

Entering the context
body
Exiting the context

当执行离开 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

执行上述代码后,您将获得以下 output

Entering the context
body
Exiting the context
An exception occurred

Asynchronous Context Managers

与同步上下文管理器类似,异步上下文管理器也使用 aenter () 和 aexit () 这两个方法实现。它们用在 async with 语句中。

The aenter(self) Method − 它必须返回一个在进入上下文时将等待的 awaitable。

aexit(self, exc_type, exc_value, traceback) Method − 它必须返回一个在退出上下文时将等待的 awaitable。

Example

下面是创建异步上下文管理器类的示例 −

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

Creating Custom Context Managers

Python 标准库中的 contextlib 模块提供了更轻松地创建上下文管理器的工具。

Using the contextlib.contextmanager() Function

contextlib.contextmanager() 函数是一个装饰器,它允许你为 with 语句上下文管理器创建工厂函数。它无需定义一个单独的类或单独实现 enter()exit() 方法。

Example

下面是一个使用 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

Using the contextlib.asynccontextmanager() Function

contextlib 模块还提供了专门为创建异步上下文管理器设计的 asynccontextmanager。它与 contextmanager 类似,无需分别定义一个单独的类或实现 aenter()aexit() 方法。

Example

下面是一个演示如何使用 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