2016-02-18 9 views
8

私はPythonでオブジェクトをクリーンアップするさまざまな方法について読んでいた、と私は(、21)これらの質問につまずいている基本的に__del__()を使用してクリーンアップすることは信頼できないと言うと、次のコードは避けるべきである。Pythonのクリーンアップに__del __()を使用することは信頼性がありませんか?

def __init__(self): 
    rc.open() 

def __del__(self): 
    rc.close() 

問題は、私はこのコードを正確に使用しており、上記の質問に記載されている問題は再現できません。私の知る限り、クローズドソースソフトウェア(testIDEA、誰ですか?)のためのPythonモジュールを提供しているので、私はwithステートメントで代替案に行くことができません。このソフトウェアは特定のクラスのインスタンスを作成し、これらのインスタンスは、その間にサービスを提供する準備ができている必要があります。私が見る__del__()の唯一の代替手段は、手動でopen()close()を必要に応じて呼び出すことです。これはかなりバグが多いと思われます。

インタープリタを閉じると、オブジェクトが正しく破棄されるという保証はありません。(そして、気にしないでください。それ以外は、__del__()を使って火事で遊んでいますか?

PS:当初は、質問に関するメタ情報には再現できないバグを投稿することを考えていましたが、必要な技術的な詳細は得られません。

+0

インタープリタが閉じられたときに '__exit__'が実行されることが保証されていますか? –

+0

また、私は[このリンク](http://eli.thegreenplace.net/2009/06/12/safely-using-destructors-in-python)がこの件に関して非常に役立つことを発見しました。 –

+0

@RickTeacheyあなたは '__del__'を' __exit__'と間違えましたか、私のコードで '__exit__'を使うことをお勧めしますか?また、閉鎖時に問題を許容することができます。 –

答えて

3

あなたはごみ収集の言語でファイナライザを持つ典型的な問題を観察します。 JavaにはC#があり、それに対処するにはPython withキーワードのようなスコープベースのクリーンアップメソッドを提供しています。

主な問題は、ガベージコレクタがオブジェクトのクリーンアップと破棄を担当することです。 C++では、スコープ外になるとオブジェクトが破壊されるため、RAIIを使用してセマンティクスを定義することができます。 Pythonでは、オブジェクトは範囲外になり、GCが好きな限り生きています。 Pythonの実装によっては、これは異なる場合があります。refcountingベースのGCを備えたCPythonは、(Python Python Python Python Python Python Python Python Python Python Python Python Python Python Python Python Python Python Python Python Python Python Python Python Python Python Python Python Python Python Python Python Python Python Python Python Python Python Pythonスレッド例えば

def bad_code(filename): 
    return open(filename, 'r').read() 

for i in xrange(10000): 
    bad_code('some_file.txt') 

bad_codeは、ファイルハンドルをリークします。 CPythonでは問題ありません。 refcountはゼロに落ち、すぐに削除されます。 PyPyやIronPythonでは、使用可能なすべてのファイル記述子を使い果たしてしまうため、IOErrorや同様の問題が発生する可能性があります(Unixではulimit、Windowsでは509ハンドルまで)。

クリーンアップを保証する必要がある場合は、コンテキストマネージャを使用したスコープベースのクリーンアップとwithが適しています。あなたはあなたのオブジェクトが最終決定される時を正確に知っています。しかし、このような範囲指定されたクリーンアップを簡単に実行することはできません。それは、__del__,atexitまたは類似の構造を使用して、クリーンアップ時に最善の努力をする場合です。それは信頼できるものではありませんが、何よりも優れています。

明示的なクリーンアップまたは明示的なスコープの適用をユーザに負担させるか、__del__でギャンブルを行い、今や奇妙なことを(特にインタプリタシャットダウン)見ることができます。

+0

ありがとうございます。私は実際に自分のコードでベストエフォートクリーンアップ以上のものに頼っています。あなたの例でCPythonが何を保証するのかを明確にすることができますか?開いているハンドルは1つしかありませんか?たかだか10?他に何か? –

+1

CPythonは参照カウントシステムを使用してクリーンアップを処理します。したがって、上記の例では、ハンドルが範囲外になり、refcountが減り、すぐにクリーンアップされるため、関数が実行されている間はハンドルが1つだけ開いています。 – schlenk

+0

それは私のために十分です。私は特定のPythonインタプリタが自分のコードを実行するための要件を取り除くことができます。 –

2

__del__を使用してコードを実行する場合、いくつかの問題があります。

参考文献を積極的に追跡していても、コード全体で手動でガベージコレクションを開始しない限り、すぐに実行される保証はありません。私はあなたについて知らないが、自動ガベージコレクションは、参照を正確に追跡するという点で私を傷つけている。あなたのコードに徹底的に取り組んでいても、他のユーザーに頼ることになります。このコードでは、参照カウントと同じようにコードを使用します。

2つで、__del__が実行されない場合が2つあります。オブジェクトが初期化されて作成されている間に例外がありましたか?通訳はやめましたか?どこかに循環参照がありますか?うん、ここで間違っているかもしれないたくさんのこと、きれいに一貫してそれに対処する方法はほとんどありません。

3つは実行されても例外を発生させないため、他のコードと同様に例外を処理することはできません。さまざまなオブジェクトのメソッドが特定の順序で実行されることを保証することもほぼ不可能です。だから、大量のオブジェクトをクリーンアップしたり削除したりするデストラクタの最も一般的な使用例は無意味で、計画どおりに実行することはできません。

あなたが実際に実行するコードをしたい場合は、はるかに優れたメカニズムがある - コンテキストマネージャ、信号/スロット、イベントなど

+0

__init__で例外について詳しく説明できますか?私はキャッチして、再スローする必要がありますか?私は 'with'が行く方法を知っていますが、閉鎖されたソース呼び出し元にオブジェクトを提供する必要がありますので、私のオプションは制限されているようです –

+0

'__init__'を作成または実行していて、 '__init__'は完了せず、そのクラスへの参照は決して生成されないので、エラーが発生する前に作成したものをすべて破棄またはクリーンアップするために' __del__'が呼び出されることはありません。あなたが提供しなければならないオブジェクトの仕様は何ですか?クローズドソースライブラリのドキュメントを教えてください。 –

+0

見たい場合は、[このページ](http://www.isystem.com/downloads/testIDEA/help/)にいくつかの情報があります。関連するセクションは、Tasks-> Writing Script Extensionsです。 –

関連する問題