Python - Context Managers

Context managers trong Python cung cấp một cách mạnh mẽ để quản lý tài nguyên một cách hiệu quả và an toàn. Một context manager trong Python là một đối tượng định nghĩa một ngữ cảnh chạy để sử dụng với câu lệnh with . Nó đảm bảo rằng các thao tác thiết lập và dọn dẹp được thực hiện tự động.

Ví dụ, khi làm việc với các thao tác tệp, các trình quản lý ngữ cảnh xử lý việc mở và đóng tệp, đảm bảo rằng tài nguyên được quản lý đúng cách.

How Context Managers Work?

Các trình quản lý ngữ cảnh trong Python hoạt động bằng cách triển khai các phương thức __enter__() __exit__() (hoặc các phương thức tương đương bất đồng bộ cho các thao tác async). Các phương thức này đảm bảo rằng tài nguyên được lấy và giải phóng một cách chính xác. Ngoài ra, mô-đun contextlib của Python còn đơn giản hóa việc tạo ra các trình quản lý ngữ cảnh tùy chỉnh.

Example

Dưới đây là một ví dụ đơn giản minh họa cách một trình quản lý ngữ cảnh hoạt động với các thao tác tệp trong Python.

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

Trong ví dụ này, một tệp được mở ở chế độ ghi, và sau đó tự động đóng khi khối bên trong câu lệnh with được thoát.

Python Context Manager Types

Python hỗ trợ cả trình quản lý ngữ cảnh đồng bộ và bất đồng bộ. Mỗi loại có các phương thức cụ thể cần được triển khai để quản lý vòng đời của ngữ cảnh.

Synchronous Context Managers

Các trình quản lý ngữ cảnh đồng bộ được thực hiện bằng cách sử dụng các phương thức __enter__() __exit__() .

1. The __enter__() Method

Phương thức __enter__(self) được gọi khi thực thi vào ngữ cảnh của câu lệnh with. Phương thức này nên trả về tài nguyên sẽ được sử dụng trong khối with.

Example

Dưới đây là một ví dụ đơn giản về việc tạo quản lý ngữ cảnh của riêng chúng ta bằng cách sử dụng các phương thức __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")

Khi thực thi đoạn mã trên, bạn sẽ nhận được output

Entering the context
body
Exiting the context

2. The __exit__() Method

Phương thức __exit__(self, exc_type, exc_value, traceback) được gọi khi thực thi rời khỏi ngữ cảnh của câu lệnh with. Nó có thể xử lý các ngoại lệ nếu có xảy ra, và nó trả về một cờ Boolean cho biết liệu ngoại lệ có nên bị подавлено hay không.

Ví dụ này minh họa cách tạo trình quản lý ngữ cảnh của riêng chúng ta và cách các phương thức __exit__() xử lý các ngoại lệ.

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

Trong khi thực thi đoạn mã trên, bạn sẽ nhận được output

Entering the context
body
Exiting the context
An exception occurred

Asynchronous Context Managers

Tương tự như các trình quản lý ngữ cảnh đồng bộ, các trình quản lý ngữ cảnh bất đồng bộ cũng được triển khai bằng cách sử dụng hai phương thức là __aenter__() __aexit__() . Những phương thức này được sử dụng trong các câu lệnh async with .

The __aenter__(self) Method − Nó phải trả về một đối tượng có thể chờ (awaitable) mà sẽ được chờ khi vào ngữ cảnh.

__aexit__(self, exc_type, exc_value, traceback) Method − Nó phải trả về một đối tượng có thể chờ (awaitable) mà sẽ được chờ khi thoát khỏi ngữ cảnh.

Example

Dưới đây là ví dụ về việc tạo một lớp trình quản lý ngữ cảnh bất đồng bộ −

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())

Khi thực thi đoạn mã trên, bạn sẽ nhận được đầu ra sau:

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

Creating Custom Context Managers

Mô-đun contextlib trong thư viện chuẩn của Python cung cấp các tiện ích để tạo các trình quản lý ngữ cảnh dễ dàng hơn.

Using the contextlib.contextmanager() Function

Hàm contextlib.contextmanager() là một decorator cho phép bạn tạo ra các hàm factory cho các trình quản lý ngữ cảnh với câu lệnh with. Nó loại bỏ nhu cầu định nghĩa một lớp riêng biệt hoặc triển khai các phương thức __enter__() __exit__() một cách riêng lẻ.

Example

Dưới đây là một ví dụ sử dụng contextlib.contextmanager để tạo một hàm quản lý ngữ cảnh.

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")

Khi thực thi đoạn mã trên, bạn sẽ nhận được đầu ra sau:

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

Using the contextlib.asynccontextmanager() Function

Mô-đun contextlib cũng cung cấp asynccontextmanager, được thiết kế đặc biệt để tạo ra các quản lý ngữ cảnh bất đồng bộ. Nó tương tự như contextmanager và loại bỏ nhu cầu phải định nghĩa một lớp riêng biệt hoặc thực hiện các phương thức __aenter__() __aexit__() một cách riêng lẻ.

Example

Dưới đây là một ví dụ minh họa việc sử dụng contextlib.asynccontextmanager() để tạo một hàm quản lý ngữ cảnh bất đồng bộ.

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())

Khi thực thi đoạn mã trên, bạn sẽ nhận được đầu ra sau:

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