6

いくつかの背景:私は大銀行で働いており、変更できず、インポートするだけのPythonモジュールを再利用しようとしています。また、新しいユーティリティ/関数などをインストールするオプションもありません(LinuxでPython 2.6を実行しています)。

私は現在これを持っています:

私のモジュールでは:

from common.databaseHelper import BacktestingDatabaseHelper

class mfReportProcess(testingResource):
    def __init__(self):
        self.db = BacktestingDatabaseHelper.fromConfig('db_name')

'testingResource'クラス内で呼び出されるメソッドの1つには、次のものがあります。

 with self.db as handler:

これで倒れます:

with self.db as handler:
AttributeError: 'BacktestingDatabaseHelper' object has no attribute '__exit__'

実際、__exit__「BacktestingDatabaseHelper」クラスにはメソッドがありません。このクラスは変更できません。

しかし、私が再利用しようとしているこのコードは、他のアプリでも完全に機能します-なぜ私がこのエラーを受け取り、他に誰もいないのか誰かが知っていますか?__exit__ローカルで定義する方法はありますか?

よろしくお願いします。

追加するために編集:

DBアクセスを設定するために独自のクラスを追加しようとしましたが、機能させることができません。これをモジュールに追加しました。

class myDB(BacktestingDatabaseHelper): 
    def __enter__(self): 
        self.db = fromConfig('db_name') 
    def __exit__(self): 
        self.db.close() 

そして追加:

self.db = myDB 

メインクラスのinit属性に追加しましたが、次のエラーが発生します。

with self.db as handler:
TypeError: unbound method __enter__() must be called with myDB instance as first argument (got nothing instead)

これを適切に行う方法に関する提案はありますか?

4

5 に答える 5

11

プロトコルの使用は、で使用されるオブジェクトがコンテキストマネージャープロトコルを実装withしていることを前提としています。with

基本的に、これはクラス定義__enter__()__exit__()メソッドを定義する必要があることを意味します。これらのないオブジェクトを使用すると、Pythonは属性AttributeErrorの欠落について不平を言います。__exit__

于 2012-05-24T11:45:08.990 に答える
4

エラーは、ステートメントBacktestingDatabaseHelperで使用するように設計されていないことを意味します。withクラスのように聞こえ、相互に互換性がありません(おそらくあなたのバージョンtestingResourceは古くなっています)。BacktestingDatabaseHelpercommon.databaseHelper

于 2012-05-24T11:44:29.807 に答える
3

ステートメントを変更することはできないため、適切な関数を追加する派生withクラスを追加し、代わりにこれを使用する必要があります。BacktestingDatabaseHelper__enter__()__exit__()

これは、オリジナルにできるだけ近づけようとする例です。

class myDB(BacktestingDatabaseHelper): 
    def __enter__(self): 
        return self
    def __exit__(self): 
        self.db.close()
    def fromConfig(self, name):
        x = super(myDB, self).fromConfig(name)
        assert isinstance(x, BacktestingDatabaseHelper)
        x.__class__ = myDB # not sure if that really works
[...]
self.db=myDB.fromConfig('tpbp')

__enter__しかし、問題は、何が返されるのかわからないことです。たとえばMySQLdb、接続のコンテキストマネージャは、1つのトランザクションを表すカーソルを作成します。ここでもそうだとしたら、何か他のことを考えなければなりません...

于 2012-05-24T11:55:29.297 に答える
2

'with'キーワードは、基本的に次のように書き出すためのショートカットです。

try:
    // Do something
finally:
    hander.__exit__()

handlerこれは、オブジェクトがリソース(たとえば、開いているファイルストリームなど)を使い果たしている場合に役立ちます。「何かをする」部分で何が起こっても、リソースがクリーンに解放されるようにします。

あなたの場合、ハンドラオブジェクトには__exit__メソッドがないため、with失敗します。BacktestingDatabaseHelperを使用していないので、他の人も使用できると思いますwith

今できることについては、オブジェクトに独自のバージョンを追加するのではなく、忘れwithて使用することをお勧めします。ハンドラーを適切に解放することを確認する必要があります(これをどのように行うかは、使用方法によって異なります)。try ... finally__exit__BacktestingDatabaseHelper

try:
    handler = self.db
    // do stuff
finally:
    handler.close()

編集:変更できないので、@DanielRosemanがラップするように提案BacktestingDatabaseHelperしているようなことをする必要があります。(上記のように)クリーンアップするのに最適な方法に応じてBacktestingDatabaseHelper、次のように記述できます。

from contextlib import contextmanager

@contextmanager
def closing(thing):
    try:
        yield thing
    finally:
        thing.close()

そしてこれを次のように使用します:

class mfReportProcess(testingResource):
    def __init__(self):
        self.db = closing(BacktestingDatabaseHelper.fromConfig('db_name'))

(これはドキュメントから直接です)。

于 2012-05-24T11:49:58.103 に答える
2

contextlib.contextmanagerデコレータを試してオブジェクトをラップし、コンテキストマネージャプロトコルをサポートすることをお勧めします。

于 2012-05-24T11:54:02.590 に答える