PythonでWith構文に対応したクラスを作成する方法

Python

PythonでWith構文を利用すると、呼び出し側で明示的に「初期処理」、「終了処理」を呼び出さなくても自動的に実行されるようになります。

ファイルやデータベースへのアクセスで終了処理を呼び忘れClose漏れにならないようにすることなどが簡単にできます。

PythonでWith構文に対応したクラスを作成するには「__enter__()」と「__exit__()」メソッドを実装します。

PythonでWith構文に対応したクラスのクラスを作成する方法

PythonでWith構文を使うと利用者に初期処理と終了処理を意識させることなく、クラス側で安全に初期処理と終了処理を確実に実行するようにできるようになります。

With構文に対応したクラスを作成するには「__enter__()」と「__exit__()」メソッドを実装するこで実現できます。。

With構文__enter__と__exit__の実装方法

実際にPythonのWith構文で必要な__enter__と__exit__メソッドを実装してみます。

今回はsqlite3のデータベースに対してのアクセスするクラスをWith構文で実装します。

import sys
import sqlite3

class WithTestClass( object ):
    def __enter__( self ) :
        print( self.__class__.__name__ + ".__enter__():Start" )

        #開始処理
        try :
            self.db = sqlite3.connect( ":memory:" )
            self.db.execute( "CREATE TABLE test_table ( name TEXT, age INTEGER )" )
            self.db.execute( "INSERT INTO  test_table VALUES ( 'トラスト太郎', 25 )" )
            self.db.execute( "INSERT INTO  test_table VALUES ( 'トラスト次郎', 27 )" )
            self.db.execute( "INSERT INTO  test_table VALUES ( 'トラスト三郎', 30 )" )
            self.db.execute( "INSERT INTO  test_table VALUES ( 'トラスト花子', 20 )" )
        except Exception as e:
            self.db = None

        print( self.__class__.__name__ + ".__enter__():End" )

        return self

    #終了処理にあたる__exit__メソッド
    def __exit__( self, exc_type, exc_val, exc_tb):
        print( self.__class__.__name__ + ".__exit__():Start" )
        #終了処理
        if self.db != None :
            self.db.close()

        print( self.__class__.__name__ + ".__exit__():End" )

    #データベースに対してSQLを実行する
    def execute( self, sql ) :
        return self.db.execute( sql )

このクラスを利用する場合は

with WithTestClass() as db:
    try :
        result = db.execute( "SELECT * FROM test_table order by age" )
        print( "SELECTした結果は" + str(result.fetchall()) )
    except Exception as e:
        raise

のように「with」で利用するクラス名を指定し、そのインスタンス名を「as」で指定します。

上記のソースを実行すると

WithTestClass.__enter__():Start
WithTestClass.__enter__():End
SELECTした結果は[('トラスト花子', 20), ('トラスト太郎', 25), ('トラスト次郎', 27), ('トラスト三郎', 30)]
WithTestClass.__exit__():Start
WithTestClass.__exit__():End

となり、「__enter__ → withブロック内 → __exit__」と処理が実行されいることがわかります。

以上、PythonでWith構文に対応したクラスを作成する方法でした。