PythonのWith構文に対応したクラス(コンテキストマネージャー)を作成する方法
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構文に対応したクラスを作成する方法でした。
リンク