Python コンテキスト マネージャー: ブロックを使用したカスタムの作成

Python でカスタム コンテキスト マネージャーを作成する方法を学びます。リソースの安全性を確保するために、contextmanager デコレーターと __enter__/__exit__ メソッドをマスターします。

エディターで試してみる

概要

コンテキスト マネージャーは、外部リソースのセットアップと破棄を処理するために設計された Python のエレガントなメカニズムです。ソフトウェアでは、多くの操作で、ファイルのオープンとクローズ、データベースへの接続と切断、ロックの取得と解放などのアクションのペアが必要です。セットアップ ステップの後、ティアダウン ステップの前にプログラムがクラッシュした場合、それらのリソースはメモリ内にロックされたままになります。コンテキスト マネージャーは、あらゆる状況下でリソースが安全にクリーンアップされることを保証します。

コンテキスト マネージャーを呼び出す標準的な方法は、「with」ステートメントを使用することです。内部では、「with」ステートメントで使用されるオブジェクトはすべてコンテキスト マネージャー プロトコルを実装する必要があります。このプロトコルは、`__enter__()` と `__exit__()` という 2 つの特別なメソッドで構成されます。 `with` ブロックが始まると、リソースを準備するために `__enter__()` が呼び出されます。 `with` ブロックが終了するか例外が発生すると、`__exit__()` が自動的にトリガーされ、発生した例外に関する情報を受け取るため、クリーンアップを処理したりエラーを抑制したりできます。

単純な使用例の場合、`__enter__` メソッドと `__exit__` メソッドを使用してクラスを作成すると冗長に感じることがあります。これを簡素化するために、Python の標準ライブラリには、`@contextmanager` デコレータを備えた `contextlib` モジュールが提供されています。このデコレータを使用すると、単一の `yield` ステートメントを含む単純なジェネレータ関数を作成できます。 「yield」の前のコードはセットアップとして機能し、生成された値はリソースとして機能し、「yield」の後のコードはクリーンアップを表します。コンテキスト マネージャーをマスターすると、アプリケーションのリークが確実になくなります。

コードと実行の出力

実行ログ境界を管理するために __enter__ と __exit__ を実装するカスタム クラス。

class CustomManager:
    def __enter__(self):
        print("--> Resource Setup: Entering the block")
        return "RESOURCE_KEY"

    def __exit__(self, exc_type, exc_value, traceback):
        print("<-- Resource Teardown: Exiting the block")
        if exc_type:
            print(f"Exception Intercepted: {exc_value}")
        return True  # Suppress exceptions

with CustomManager() as res:
    print(f"Working inside block with resource: {res}")
    # Force an error to verify exception handling
    x = 1 / 0
print("Program continues running safely.")
端子出力
--> Resource Setup: Entering the block
Working inside block with resource: RESOURCE_KEY
<-- Resource Teardown: Exiting the block
Exception Intercepted: division by zero
Program continues running safely.

段階的な実装

  • データベーストランザクションの管理 (成功時にコミット、エラー時にロールバック)
  • マルチスレッドコードでのスレッドロックの取得と解放
  • 単体テストスクリプト中の標準出力 (stdout) のリダイレクト

よくある質問

カスタム コンテキスト マネージャーで例外を抑制するにはどうすればよいですか?

__exit__ メソッドから True を返すことによって。 True を返す場合、ブロック内で発生した例外は抑制されます。

複数のコンテキスト マネージャーを 1 つのステートメントに結合できますか?

はい、カンマで区切ることができます。たとえば、open('file1.txt') を f1、open('file2.txt') を f2: とします。

関連トピック

推奨される Python リソース

関連するインタラクティブなチュートリアル、チートシート、コード比較で知識を深めてください。