私は検索しましたが、__enter__
(または__exit__
?)/ __init__
ではなくpythonの__new__
/__del__
を使用する十分な理由を思い付くことができません。
__enter__
/__exit__
はwith
ステートメントをコンテキストマネージャーとして使用するためのものであり、with
ステートメントはすばらしいと理解しています。しかし、これに対応するのは、それらのブロック内のコードはonlyがそのコンテキストで実行されるということです。 __init__
/__del__
の代わりにこれらを使用することにより、with
を使用する必要がある呼び出し元との暗黙のコントラクトを作成しているように見えますが、そのようなコントラクトを強制する方法はなく、コントラクトはドキュメント(またはコード)。それは悪い考えのようです。
with
ブロック内で__init__
/__del__
を使用しても同じ効果が得られるようです。しかし、コンテキスト管理メソッドではなくそれらを使用することで、私のオブジェクトは他のシナリオでも役立ちます。
それで、私がeverコンストラクタ/デストラクタメソッドではなくコンテキスト管理メソッドを使用したいという説得力のある理由を誰かが思い付くことができますか?
このような質問をするのにより良い場所がある場合は、私に知らせてください。しかし、これについての良い情報はあまりないようです。
私は常にwith
を使用して新しいオブジェクトをインスタンス化するため、この質問は悪い(しかし一般的な可能性が高い)仮定に基づいていました。この場合、__init__/__del__
は__enter__/__exit__
(ただし、__del__
をいつ実行するかを制御できない場合を除き、ガベージコレクション次第であり、プロセスが最初に終了した場合は呼び出されない場合があります)。しかし、with
ステートメントで既存のオブジェクトを使用する場合、それらはもちろんまったく異なります。
あなたが見逃しているように見えるいくつかの違いがあります:
コンテキストマネージャは、実行中のブロックだけに新しいオブジェクトを提供する機会を得ます。一部のコンテキストマネージャーはself
を返すだけです(ファイルオブジェクトと同じように)が、たとえば、データベース接続オブジェクトは現在のトランザクションに関連付けられたカーソルオブジェクトを返す場合があります。
コンテキストマネージャは、コンテキストの終了だけでなく、例外が原因で終了が発生した場合にも通知されます。次に、そのイベントの処理を決定するか、終了時に別の方法で反応します。もう一度例としてデータベース接続を使用すると、例外があることに基づいて、トランザクションをコミットまたは中止できます。
__del__
は、オブジェクトへのall参照が削除された場合にのみ呼び出されます。つまり、その存続期間を制御する場合もしない場合もある複数の参照が必要な場合、その呼び出しに依存することはできません。ただし、コンテキストマネージャ出口は正確に定義されています。
コンテキストマネージャは再利用でき、状態を保持できます。再びデータベース接続。一度作成してから、コンテキストマネージャとして何度も使用すると、接続が開いたままになります。そのために毎回新しいオブジェクトを作成する必要はありません。
これは、たとえばスレッドロックにとって重要です。あなたhaveは状態を保持し、一度に1つのスレッドのみがロックを保持できるようにします。これを行うには、oneロックオブジェクトを作成し、次にwith lock:
を使用して、そのセクションを実行するさまざまなスレッドがそれぞれそのコンテキストに入る前に待機するようにします。 。
__enter__
メソッドと__exit__
メソッドは、コンテキストマネージャプロトコルを形成します。これらを実際に使用するのは、環境。コンテキストマネージャの目的は、単一のインスタンスの存続期間を管理することではなく、一般的なtry...finally
およびtry...except
パターンを簡略化することです。 PEP 343 –「with」ステートメント を参照してください:
このPEPは、Python言語に "with"という新しいステートメントを追加して、try/finallyステートメントの標準的な使用を除外できるようにします。
_del x
_はx.__del__()
を直接呼び出しません
_.__del__
_がいつ呼び出されるか、または実際には まったく呼び出されるかどうか を制御することはできません。
したがって、コンテキスト管理に___init__
_/___del__
_を使用することは信頼できません。
__init__
/__del__
の代わりにこれらを使用することで、呼び出し元との暗黙のコントラクトを作成しているように見えますが、with
を使用する必要がありますが、そのようなコントラクトを強制する方法はありません
あなたはどちらかの方法で契約を結んでいます。ユーザーが使用後にクリーンアップが必要であることに気づかずにオブジェクトを使用すると、クリーンアップの実装方法に関係なく、ユーザーは物事を台無しにします。たとえば、__del__
の実行を妨げるなど、オブジェクトへの参照を永久に保持する可能性があります。
特別なクリーンアップが必要なオブジェクトがある場合は、この要件を明示的にする必要があります。ユーザーにwith
機能と明示的なclose
または同様のメソッドを提供して、クリーンアップの発生時期をユーザーが制御できるようにする必要があります。 __del__
メソッド内でクリーンアップ要件を非表示にすることはできません。安全対策として__del__
を実装することもできますが、__del__
の代わりにwith
または明示的なclose
。
そうは言っても、Pythonは__del__
が実行されるという約束を一切しません。標準の実装は、オブジェクトの参照カウントが0に下がったときに__del__
を実行しますが、参照がスクリプトの最後まで存続する場合、またはオブジェクトが参照サイクル内にある場合に発生します。他の実装では参照カウントを使用しないため、__del__
の予測がさらに困難になります。