10

それ自体でコンテキストマネージャーとして機能するクラス「A」があるとしましょう。

def __enter__()
def __exit__()

インターフェース。withクライアント コードがステートメントを使用して直接 'A' オブジェクトを作成することは有効です。

現在、他の機能をカプセル化し、「A」オブジェクトを利用する別のクラス「B」もあります。

「B」をコンテキスト マネージャーとしても機能させたい場合、「A」インスタンスを管理する正しい方法は何ですか?

'B' 呼び出しの実装と(それぞれ) その A オブジェクト インスタンスの実装は必要__enter__ですか? それとももっと良い方法がありますか?__exit____enter____exit__

具体的な例を挙げると (これは私のアプリケーションで使用しているものではありません。頭に浮かんだ最初の非抽象的な例です)、2 つのクラスを考えます。

  • DatabaseConnection
  • DatabaseConnectionPool

DatabaseConnection単一のものを単独で使用することは有効であるためDatabaseConnection、context-manager インターフェースを実装します。

DatabaseConnectionPoolDatabaseConnections他のビットとボブだけでなく、いくつかを利用します。を使用するDatabaseConnectionPoolと (つまり、"with" で)、そのインスタンスのセットアップと破棄が行われDatabaseConnectionます (その他に必要なことは何でも実行されます)。

更新: 次の出力が得られることを望んでいたテスト コードをいくつか作成しました。

Enter は Outer で呼び出されます
インナーで呼び出された入力
外部コンテキスト内で...
do_foo が呼び出されました!
まだアウターを使っている...
内部で呼び出される終了
外部で呼び出された終了
アウターを使って完成

しかし、私は以下を得ました:

Enter は Outer で呼び出されます
インナーで呼び出された入力
内部で呼び出される終了
外部コンテキスト内で...
do_foo が呼び出されました!
まだアウターを使っている...
外部で呼び出された終了
アウターを使って完成

コード:


class Inner(object):
  def __enter__(self):
    print "Enter invoked on Inner"
    return self

  def __exit__(self, typ, val, tb):
    print "Exit invoked on inner"

  def do_foo(self):
    print "do_foo invoked!"

class Outer(object):
  def __init__(self):
    self._inner = Inner()

  def __enter__(self):
    print "Enter invoked on Outer"

    with self._inner as ctx:
      return self

  def __exit__(self, typ, val, tb):
    print "Exit invoked on outer"

with Outer() as outer:
  print "Within outer context..."
  outer._inner.do_foo()
  print "Still using outer..."

print "Done using outer"

これを機能させる方法についてのアイデアはありますか?

4

2 に答える 2

0

それは本当に設計上の問題であり、判断の呼びかけです。次のことを提案します。

プール クラス インスタンスはコンテキストを提供し、必要に応じてプログラムで DB 接続インスタンスを使用します。__enter__しかし、それは単に DB インスタンスごとに呼び出すよりも少し複雑です__exit__。それを試みる必要はないと思います。それらはその目的を意図したものではありません。この場合、DB インスタンスのコンテキストマネージャーを直接使用することをお勧めします。

コンテキスト マネージャーを使用する場合は、次のようにします。

def __enter__(self):
    for db in self.pool:
        with db as d:
            d.transaction()

def __exit__(self, type, value, traceback):
    pass 

ただし、エラー処理を自分で行いたい場合は、次のようにします。

def __enter__(self):
    for db in self.pool:
        try:
            db.connection()
            # ... write and transact here

def __exit__(self, type, value, traceback):
    if type is None: # no errors, so close as normal
        for db in self.pool:
            db.close()
    # ... more code here for proper error handling
于 2014-06-16T00:29:10.137 に答える
0

FWIW、私は同じ設計上の考慮事項を持っていたので、「子」クラスに exit および enter 関数を記述し、「親」クラスのみをコンテキストマネージャーにしました。

(あなたの質問を正しく理解していれば、「親コンテキストマネージャーを閉じたときに、コンテキストマネージャークラスで使用したすべてのクラスをエレガントに閉じるにはどうすればよいですか?」)

于 2022-02-21T22:39:27.543 に答える