Python

【Python】自作クラスをwith文で使う方法【コンテキストマネージャ】

この記事では、Pythonのユーザー定義クラスをwith文で使えるようにする方法を解説します。with文を使うことで、前処理と後処理を安全に実行することができます。with文で使えるようにするには、クラスにコンテキストマネージャを実装します。それでは、実装方法を見ていきましょう!

コンテキストマネージャとは

コンテキストマネージャとは、with文の実行時に前後処理するオブジェクトのことを言います。例えば、ファイルオブジェクトはコンテキストマネージャです。

コンテキストマネージャは、以下のようにwith文で使用可能です。

with open('ファイル名', 'モード') as f:
    # ファイルの中身を読み込んだり書き込んだり

open()関数によって返されたファイルオブジェクトがfに格納され、with文ブロック内で使用可能です。また、close()メソッドで明示的にファイルを閉じなくても、ブロックを抜ける際に後処理で勝手に閉じてくれます。

このように、決まった前後処理が必要なオブジェクトをコンテキストマネージャにすることで、後処理を忘れることがなくなり、なおかつ記述が楽になります。

with文で使えるようにするには、2つのメソッドをクラスに実装することで実現できます。

コンテキストマネージャを定義する

クラスに、以下の2つの特殊メソッドを定義します。

__enter__(self):

このメソッドはwith文のコードブロックを処理する前に実行されます。

__exit__(self, exc_type, exc_value, traceback):

このメソッドはwith文のコードブロックを抜ける際に実行されます。引数にはコードブロック内で例外が発生した際の詳細が格納されます。例外が発生しなかった場合はNoneが格納されます。

自作クラスにコンテキストマネージャを定義し、with文で使ってみます。

class ContextManager:

    def __enter__(self):
        print('前処理')

    def __exit__(self, exc_type, exc_value, traceback):
        print('後処理')


with ContextManager():
    print('with文のコードブロック内')

実行結果

前処理
with文のコードブロック内
後処理

戻り値を使用する場合

with文ブロック内で何かしら使用したいオブジェクトがある場合、__enter__()メソッドで戻り値として返すことで、asで繋げた識別子に渡すことができる。

with ContextManager() as 識別子:
    # ブロック内で識別子を使用可能

例えば以下のコードでは、戻り値として文字列を渡し、ブロック内で出力している。

class ContextManager:

    def __enter__(self):
        print('前処理')
        return '__enter__の戻り値です'  # 戻り値を定義

    def __exit__(self, exc_type, exc_value, traceback):
        print('後処理')


with ContextManager() as text:
    print(text)

実行結果

前処理
__enter__の戻り値です
後処理

with文ブロック内で例外が発生した場合

with文のコードブロック内で例外が発生しても、__exit__()メソッドは実行されます。なので、後処理は必ず実行することが可能です。

ブロック内で例外を発生させて__exit__()メソッドが処理されるか確認してみましょう。ついでに、引数にどのような値が格納されているか出力してみます。

class ContextManager:

    def __enter__(self):
        pass

    def __exit__(self, exc_type, exc_value, traceback):
        print(exc_type)
        print(exc_value)
        print(traceback)


with ContextManager():
    # 例外を故意に起こす
    raise ValueError('エラー発生')

実行結果

<class 'ValueError'>
エラー発生
<traceback object at 0x1054eab40>

まとめ

この記事では、Pythonのユーザー定義クラスをwith文で使えるようにするためにコンテキストマネージャを定義する方法解説しました。

コンテキストマネージャを使うことで、強力に前処理と後処理を定義することができます。特に後処理は例外が発生した場合でも実行してくれるので安心ですね❗️

実装する機会は少ないかもしれませんが、選択肢の1つとして覚えておきましょう!

それでは今回の内容はここまでです。ではまたどこかで〜( ・∀・)ノ

【Python】デコレーターの定義方法と使い方を解説 この記事では、Pythonのデコレーターの使い方を解説します。デコレーターとは、関数をラップするための機能です。関数にデコレーターを...
最短3か月でエンジニア転職『DMM WEBCAMP COMMIT』