2011-11-21 13 views
5

[私は無題のタイトルをお詫び申し上げます。私はもっ​​と良いものを考え出すことができませんでした。より良いタイトルのための提案は大歓迎です。]クラスにwith文のような機能を与えるには?

HDF5ファイルロックを使用してマルチプロセスレベルの同時実行をサポートするファイルへのインターフェイスを実装したいと思います。このモジュールの意図する環境は、NFSを介して共有ディスクにアクセスするLinuxクラスタです。目標は、複数の異なるホスト上で実行されている複数の並列プロセスによって、同じファイルへの同時アクセス(NFS経由)を可能にすることです。

h5py.Fileクラスのラッパークラスを使用してロック機能を実装したいと考えています。 (h5pyはすでにスレッドレベルの同時実行をサポートを提供していますが、根本的なHDF5ライブラリはスレッドセーフではありません。)私は精神こので何かを行うことができれば

はそれは素晴らしいことだ:

class LockedH5File(object): 
    def __init__(self, path, ...): 
     ... 
     with h5py.File(path, 'r+') as h5handle: 
      fcntl.flock(fcntl.LOCK_EX) 
      yield h5handle 
     # (method returns) 

私は上記のコードが間違っていることを認識していますが、主な考え方を伝えることを願っています。つまり、式LockedH5File('/path/to/file')をクライアントコードにオープンハンドルで渡して、さまざまな読み書き操作を実行できます。このハンドルが有効範囲外になると、デストラクタはハンドルを閉じ、ロックを解除します。

この構成に動機を与える目的は二つある。その後、クライアントによって(ハンドルに要求された事業から

  1. デカップルハンドルの作成(ライブラリコードによります)コード)、および

  2. ハンドルが閉じられていることを確認し、ロック解除、どんなに介在コードの 実行中に何が起こるか(例えば、例外、未処理の 信号、Pythonの内部エラー)。

この影響をPythonでどのように達成できますか?

ありがとうございます!

答えて

6

この作業を行うには、クラスにcontext manager protocolを実装する必要があります。あるいは、デコレータcontextlib.contextmanagerを使用してジェネレータ関数を記述します。

class LockedH5File(object): 
    def __init__(self, path, ...): 
     self.h5file = h5py.File(path, 'r+') 
    def __enter__(self): 
     fcntl.flock(fcntl.LOCK_EX) 
     return self.h5file 
    def __exit__(self, exc_type, exc_val, exc_tb): 
     self.h5file.close() 
2

まあ、コンテキストマネージャとwith声明:

あなたのクラスは、おおよそこの(h5py使用方法の詳細については、おそらく恐ろしく間違っている)ように見えるかもしれません。一般に、Pythonのデストラクタではがすべてであることが保証されていないので、フェイルセーフクリーンアップ以外のものとしてそれらを使用すべきではありません。 __enter____exit__方法を提供し、コンテキストマネージャと呼ばれているwith文で使用することができます

with LockedFile(...) as fp: 
    # ... 
8

オブジェクトのようにそれを使用します。シンプルなインターフェイスを実装しています。彼らは引数を取らず何も返さない(as部分の変数に代入される)メソッドと、3つの引数をとる__exit__メソッドの2つのメソッドを提供しなければなりません(これは結果で埋められます) sys.exc_info())、例外が処理されたことを示す0以外の値を返します。例は次のようになります:

class LockedH5File(object): 
    def __init__(self, path, ...): 
     self.path = path 

    def __enter__(self): 
     self.h5handle = h5handle = h5py.File(self.path, 'r+') 
     fcntl.flock(fcntl.LOCK_EX) 
     return h5handle 

    def __exit__(self, exc_type, exc_info, exc_tb): 
     self.h5handle.close() 
関連する問題