Menu
Coddy logo textTech

コンテキストマネージャ

CoddyのPythonジャーニー「Object Oriented Programming」セクションの一部 — レッスン 41/64。

コンテキストマネージャを使用すると、必要な時にリソースを正確に割り当て、解放することができます。これらは、エラーが発生した場合でも適切なクリーンアップを確実に行います。

以下は、with 文を使用した最も一般的な例です:

with open('example.txt', 'w') as file:
    file.write('Hello, world!')
# ファイルはここで自動的に閉じられます

例外が発生した場合でも、ファイルはブロックの終了後に自動的に閉じられます。

__enter__ メソッドと __exit__ メソッドを実装して、独自のコンテキストマネージャを作成します:

class MyContext:
    def __enter__(self):
        print("Entering the context")
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("Exiting the context")
        return False  # 例外を抑制しない

作成したカスタムコンテキストマネージャを使用します:

with MyContext() as ctx:
    print("Inside the context")

出力:

Entering the context
Inside the context
Exiting the context

データベース接続のための、より実用的なコンテキストマネージャを作成します:

class DatabaseConnection:
    def __init__(self, db_name):
        self.db_name = db_name
        self.connection = None
    
    def __enter__(self):
        print(f"Connecting to {self.db_name}")
        self.connection = f"Connection to {self.db_name}"
        return self.connection
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print(f"Closing connection to {self.db_name}")
        self.connection = None

with DatabaseConnection("users_db") as conn:
    print(f"Using {conn}")
    print("Performing database operations...")

コンテキストマネージャでの例外を処理する:

class SafeContext:
    def __enter__(self):
        print("Setting up resources")
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("Cleaning up resources")
        if exc_type:
            print(f"An exception occurred: {exc_val}")
        return False  # 例外を抑制しない

with SafeContext():
    print("Working with resources")
    # raise ValueError("Something went wrong")  # テストするにはコメントを解除してください

出力:

Connecting to users_db
Using Connection to users_db
Performing database operations...
Closing connection to users_db
Setting up resources
Working with resources
Cleaning up resources

__exit__ メソッドは3つのパラメータを受け取ります:

  • exc_type: 例外の型(または None)
  • exc_val: 例外の値(または None)
  • exc_tb: 例外のトレースバック(または None)

重要なポイント: コンテキストマネージャは、リソースを管理するために __enter__ メソッドと __exit__ メソッドを使用します。with 文はこれらのメソッドを自動的に呼び出し、適切なセットアップとクリーンアップを保証します。これは、ファイル、データベース接続、および確実なクリーンアップが必要なその他のリソースに対して特に有用です。

challenge icon

チャレンジ

簡単

このチャレンジでは、コンテキストブロックの開始から終了までの経過時間を測定するコンテキストマネージャークラスを実装します。

  • timer.py - Timer クラスの実装が含まれています(このファイルを編集します)
  • driver.py - 包括的なテストケースが含まれています(変更しないでください)

timer.py 内の TODO コメントに従って Timer コンテキストマネージャーを実装してください。このクラスは以下のことを行う必要があります:

  1. コンテキストに入る時に開始時間を記録する
  2. 終了する時に終了時間を記録する
  3. 経過時間を計算して表示する

チートシート

コンテキストマネージャは、必要な時に正確にリソースを割り当てて解放し、エラーが発生した場合でも適切なクリーンアップを保証します。

自動的なリソース管理には with 文を使用します:

with open('example.txt', 'w') as file:
    file.write('Hello, world!')
# ファイルはここで自動的に閉じられます

__enter__ メソッドと __exit__ メソッドを実装することで、カスタムコンテキストマネージャを作成できます:

class MyContext:
    def __enter__(self):
        print("Entering the context")
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("Exiting the context")
        return False  # 例外を抑制しない

with MyContext() as ctx:
    print("Inside the context")

__exit__ メソッドは3つのパラメータを受け取ります:

  • exc_type: 例外の型(または None)
  • exc_val: 例外の値(または None)
  • exc_tb: 例外のトレースバック(または None)

コンテキストマネージャで例外を処理する:

class SafeContext:
    def __enter__(self):
        print("Setting up resources")
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("Cleaning up resources")
        if exc_type:
            print(f"An exception occurred: {exc_val}")
        return False  # 例外を抑制しない

自分で試してみよう

from timer import Timer
import time

# テストケースのハンドラ
test_case = input()

if test_case == "basic_test":
    # 基本機能のテスト
    with Timer():
        # 何らかの処理をシミュレート
        time.sleep(2)  # プログラムを2秒間待機させます

elif test_case == "nested_contexts":
    # ネストされたコンテキストマネージャのテスト
    with Timer():
        time.sleep(1)
        with Timer():
            time.sleep(1)

elif test_case == "exception_handling":
    # コンテキスト内での例外処理のテスト
    try:
        with Timer():
            time.sleep(1)
            raise ValueError("Test exception")
    except ValueError as e:
        print(f"Caught exception: {e}")

elif test_case == "zero_sleep":
    # 最小限の待機時間でのテスト
    with Timer():
        time.sleep(0.001)

elif test_case == "multiple_timers":
    # 複数のタイマーを順番にテスト
    with Timer():
        time.sleep(1)
    
    with Timer():
        time.sleep(0.5)
    
    with Timer():
        time.sleep(2)

elif test_case == "as_decorator":
    # 関数コンテキスト内でのタイマーのテスト
    def timed_function():
        with Timer():
            time.sleep(2)
    
    timed_function()

else:
    # デフォルトのテスト - 基本機能
    with Timer():
        # 何らかの処理をシミュレート
        time.sleep(2)  # プログラムを2秒間待機させます
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

Object Oriented Programmingのすべてのレッスン