9

存続期間を通じてアクティブな内部データベース接続を持つオブジェクトがあります。プログラムの実行の最後に、接続をコミットして閉じる必要があります。これまで明示的なcloseメソッドを使用してきましたが、これは、特に呼び出し元のコードで例外が発生する可能性がある場合は、やや面倒です。

クロージングの方法を考えてい__del__ますが、オンラインで読んだ後、心配です。これは有効な使用パターンですか?内部リソースが__del__正しく解放されることを確認できますか?

この議論は同様の質問を提起しましたが、満足のいく答えは見つかりませんでした。私のオブジェクトはopen-play-closeのように単純に使用されるのではなく、それを使用する別のより大きなオブジェクトのメンバーとして保持されるため、明示的なcloseメソッドは必要ありません。 withGUIでの実行中。

C ++には、リソースを安全に解放できる完全に機能するデストラクタがあるので、Pythonにも合意されたものがあると思います。何らかの理由でそうではないようで、コミュニティの多くは反対を誓い__del__ます。では、代替案は何ですか?

4

2 に答える 2

8

withステートメントを読んでください。あなたはそのユースケースを説明しています。

ステートメントで使用されるメソッド__enter__とメソッドを処理する「ContextManager」クラスで接続をラップする必要があります。__exit__with

詳細については、 PEP343を参照してください。


編集

「私のオブジェクトは、open-play-closeのように単純に使用されるのではなく、別のより大きなオブジェクトのメンバーとして保持されます。」

class AnObjectWhichMustBeClosed( object ):
    def __enter__( self ):
        # acquire
    def __exit__( self, type, value, traceback ):
        # release
    def open( self, dbConnectionInfo ):
        # open the connection, updating the state for __exit__ to handle.

class ALargerObject( object ):
    def __init__( self ):
        pass
    def injectTheObjectThatMustBeClosed( self, anObject ):
        self.useThis = anObject

class MyGuiApp( self ):
    def run( self ):
        # build GUI objects
        large = ALargeObject()
        with AnObjectWhichMustBeClosed() as x:
            large.injectTheObjectThatMustBeClosed( x )
            mainLoop()

これを「依存性注入」や「制御の反転」と呼ぶ人もいます。他の人々はこれを戦略パターンと呼んでいます。「ObjectThatMustBeClosed」は戦略であり、より大きなオブジェクトにプラグインされます。アセンブリはGUIアプリのトップレベルで作成されます。これは、通常、データベースなどのリソースが取得される場所であるためです。

于 2009-06-10T10:51:46.730 に答える
6

モジュールはアプリケーション全体で同じオブジェクトを保持するため、接続モジュールを作成し、それを閉じる関数をatexitモジュールに登録できます。

# db.py:
import sqlite3
import atexit

con = None

def get_connection():
    global con
    if not con:
        con = sqlite3.connect('somedb.sqlite')
    atexit.register(close_connection, con)
    return con

def close_connection(some_con):
    some_con.commit()
    some_con.close()

# your_program.py
import db
con = db.get_connection()
cur = con.cursor()
cur.execute("SELECT ...")

この推測は、アプリケーションの接続が、モジュールグローバルが適切に提供する単一インスタンス(シングルトン)のように見えるという仮定に基づいています。

そうでない場合は、デストラクタを使用できます。

ただし、デストラクタはガベージコレクタと循環参照にうまく適合しません(デストラクタが呼び出される前に循環参照を自分で削除する必要があります)。そうでない場合(複数の接続が必要)、デストラクタを使用できます。循環参照を保持しないでください。循環参照を自分で壊す必要があります。

また、C++についてあなたが言ったことは間違っています。C ++でデストラクタを使用する場合、オブジェクトを定義するブロックが終了したとき(pythonのようwithに)、またはキーワードを使用したときdelete(で作成されたオブジェクトの割り当てを解除する)に呼び出されますnewclose()それ以外では、デストラクタではない明示的なものを使用する必要があります。つまり、Pythonと同じです。Pythonにはガベージコレクターがあるため、さらに「優れた」ものになります。

于 2009-06-10T11:09:59.890 に答える