Python

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

この記事では、Pythonで自作クラスをwith文で使えるようにする方法を解説します。

with文を使うことで前処理と後処理を安全に実行することができます。

with文で使えるようにするにはクラスにコンテキストマネージャを実装します。
それでは、方法を見ていきましょう!

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

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

ファイルオブジェクトは以下のように使います。

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

open関数によって返されたファイルオブジェクトが処理され、closeメソッドでファイルを閉じなくても後処理で勝手に閉じてくれます。

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

これは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文のコードブロック内
後処理

asを使用する場合

asで生成した変数には__enter__メソッドの戻り値が渡されます。

以下のように__enter__メソッドに戻り値を定義することで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文のコードブロック内で例外が発生しても、__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文で使えるようにするための方法解説しました。

今回のおさらい
  • 前処理: __enter__(self)
  • 後処理:__exit__(self, exc_type, exc_value, traceback)

クラスをコンテキストマネージャにすることで、とても強力に前処理と後処理を定義することができます。特に後処理は途中で例外が発生した場合でも実行してくれるので必ず後始末をすることができます。

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

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

【Python】デコレーターの使い方この記事では、Pythonのデコレーターの使い方を解説します。 デコレーターとは、関数をラップするための機能です。 関数にデ...
最短3か月でエンジニア転職「DMM WEBCAMP COMMIT」
なんと転職成功率98%!
今なら3日以内のカウンセリング枠を予約&参加で「1,000円分のAmazonギフト券」をプレゼント!