__del__メソッドとは何ですか、それを呼び出す方法は?


108

コードを読んでいます。__del__メソッドが定義されているクラスがあります。このメソッドはクラスのインスタンスを破棄するために使用されることを理解しました。しかし、この方法を使っているところが見つかりません。その主な理由は、この方法がどのように使用されているかわからないためですobj1.del()。だから、私の質問は__del__メソッドを呼び出す方法ですか?

回答:


167

__del__あるファイナライザは。オブジェクトへのすべての参照が削除された後のある時点でオブジェクトがガベージコレクションされたときに呼び出されます。

では簡単な場合、これはあなたが言う直後ことができdel xた場合、またはx機能が終了した後、ローカル変数です。特に、循環参照がない限り、CPython(標準のPython実装)はすぐにガベージコレクションを実行します。

ただし、これはCPythonの実装の詳細です。唯一必要な Pythonのガベージコレクションのプロパティは、それが起こるということです、すべての参照が削除されているので、必要ではないかもしれない、この現象が発生した直後まったく起こらない可能性があります

さらに、変数は、長い時間のために生きることができる多くの理由、例えばA伝播例外またはも0よりも変数の参照カウント大きなを保つことができるモジュールのイントロスペクションは、変数はの一部にすることができます参照のサイクル - CPythonのガベージコレクションで休憩最もオンすべてではありませんが、そのようなサイクル、さらには定期的にのみ。

実行が保証されていないため、実行する必要のあるコードを絶対に配置しないでください__del__()。このコードはfinallytryブロックの句またはwithステートメントのコンテキストマネージャーに属しています。しかし、そこにある有効なユースケースのための__del__オブジェクトの場合などは:X参照Yのコピーを保持し、また、Yグローバルでの参照をcachecache['X -> Y'] = Yそれがために丁寧になります)X.__del__また、キャッシュエントリを削除します。

デストラクタが必要なクリーンアップを(上記のガイドラインに違反して)提供していることがわかっている場合は、メソッドとして特別なものは何もないため、直接呼び出すことができますx.__del__()。明らかに、2回呼び出されることを気にしないことがわかっている場合にのみ、そうするべきです。または、最後の手段として、次を使用してこのメ​​ソッドを再定義できます。

type(x).__del__ = my_safe_cleanup_method  

5
参照カウントがゼロになった直後にオブジェクトを削除するCPythonの機能は「実装の詳細」であると言います。私は確信していません。その主張を裏付けるリンクを提供できますか?(つまり、太字のフォントそれ自体でかなり説得力がありますが、リンクは2番目に近い... :-)
Stuart Berg

14
CPython実装の詳細: CPythonは現在、参照カウント方式を使用しています(オプションで)循環的にリンクされたゴミの検出を遅らせています...他の実装は動作が異なり、CPythonが変更される場合があります。(docs.python.org/2/reference/datamodel.html
イリヤN。

いただきました__exit__。この文脈では?それは後か前__del__か、それとも一緒に実行されますか?
lony 2016年

1
「まったく発生しない可能性があります」には、プログラムの終了が含まれますか?
アンディヘイデン

1
@AndyHayden:__del__メソッドはプログラムの終了時にも実行されない場合があり、終了時に実行される__del__場合でも、インタープリターがあなたの周りで自己破壊を行っているときにも正しく機能するメソッドを作成するには、多くのプログラマーが適用するよりも注意深いコーディングが必要です。(CPythonクリーンアップは通常__del__、インタープリターのシャットダウン時に実行するメソッドを取得しますが、それでも十分でない場合があります。デーモンスレッド、Cレベルグローバル、および__del__別のもので作成されたオブジェクト__del__はすべて、__del__メソッドが実行されない
原因となる

80

これはより正確な質問ですが、別の質問の回答を書きました。

コンストラクタとデストラクタはどのように機能しますか?

これは少し意見が分かれた回答です。

使用しないでください__del__。これはC ++やデストラクタ用に構築された言語ではありません。__del__Python 3.xではこのメソッドは実際になくなるはずですが、誰かが意味のあるユースケースを見つけると私は確信しています。を使用する必要がある場合は__del__http//docs.python.org/reference/datamodel.htmlの基本的な制限に注意してください。

  • __del__ガベージコレクターがたまたまオブジェクトを収集しているときに呼び出されますdel object。オブジェクトへの最後の参照を失ったときや、を実行したときではありません。
  • __del____del__これがメソッド解決順序(MRO)であるのか、各スーパークラスを呼び出すだけなのかは明確ではありませんが、スーパークラスでanyを呼び出す責任があります。
  • __del__ガベージコレクターは、リンクリストへの最後の参照を失うなど、循環リンクの検出とクリーニングをあきらめることを意味します。gc.garbageから無視されたオブジェクトのリストを取得できます。サイクルを完全に回避するために、弱参照を使用できる場合があります。これは時々議論されます:http : //mail.python.org/pipermail/python-ideas/2009-October/006194.htmlを参照してください
  • __del__関数は、オブジェクトへの参照を保存し、ガベージコレクションを停止し、ごまかすことができます。
  • で明示的に発生した例外__del__は無視されます。
  • __del____new__よりはるかに補完し__init__ます。これは混乱を招きます。説明と落とし穴については、http://www.algorithm.co.il/blogs/programming/python-gotchas-1- del -is-not-the-opposite-of- init /を参照してください
  • __del__Pythonで「愛されている」子ではありません。sys.exit()のドキュメントには、終了する前にガベージを収集するかどうかが指定されておらず、多くの奇妙な問題があることがわかります。__del__on globalsを呼び出すと、http://bugs.python.org/issue5099などの奇妙な順序の問題が発生します。必要がある__del__場合にも呼ば__init__失敗?長いスレッドについては、http://mail.python.org/pipermail/python-dev/2000-March/thread.html#2423を参照してください

しかし、一方で:

そして、その__del__機能が気に入らない私の個人的な理由。

  • 誰かが取り上げる__del__たびに、それは30の混乱メッセージに発展します。
  • Zen of Pythonでこれらの項目を破壊します。
    • シンプルは複雑よりも優れています。
    • 特別なケースは、ルールを破るほど特別なものではありません。
    • エラーは黙って渡ってはなりません。
    • あいまいな状況に直面して、推測する誘惑を拒否してください。
    • それを行うための明白な方法は1つ(できれば1つだけ)あるはずです。
    • 実装の説明が難しい場合は、悪い考えです。

したがって、使用しない理由を見つけてください__del__


6
質問が正確ではない場合でも、なぜを使用するの__del__ではなく、どのように呼び出すかについて__del__、あなたの答えは興味深いです。
nbro 2015年

ありがとう。時には、最良のアイデアはひどいアイデアから離れることです。
Charles Merriam

他のニュースで、私はPyPy(長時間実行するアプリの高速インタープリター)がdelで中断することを忘れていました。
Charles Merriam 2017年

壊れたリンクを更新してくれて@Gloinに感謝します!
Charles Merriam

@CharlesMerriam回答ありがとうございます
トム・バロウズ

13

この__del__メソッドは、オブジェクトがガベージコレクションされたときに呼び出されます。ただし、必ずしも呼び出されるとは限りません。次のコードは、それだけでは必ずしも機能しません。

del obj

その理由はdel、参照カウントを1つだけ減らすためです。他の何かがオブジェクトへの参照を持っている場合、__del__呼び出されません。

__del__ただし、いくつかの注意事項があります。一般的に、それらは通常、あまり役に立ちません。closeメソッドまたはwithステートメントを使用したいように思えます。

メソッドに関するPythonのドキュメントを__del__参照してください。

もう1つ注意 __del__する必要があるのは、メソッドを使いすぎるとガベージコレクションが禁止されることです。特に、__del__メソッドを持つ複数のオブジェクトを持つ循環参照は、ガベージコレクションされません。これは、ガベージコレクターが最初に呼び出すものを認識していないためです。詳細については、gcモジュールのドキュメントを参照してください。


8

__del__あなたのオブジェクトが最終的に破棄されたときの方法は、(ノートスペル!)と呼ばれています。技術的に言えば(cPythonで)、オブジェクトへの参照がなくなったとき、つまりオブジェクトがスコープから外れたときです。

オブジェクトを削除して__del__メソッドを呼び出す場合は、use

del obj1

これにより、オブジェクトが削除されます(オブジェクトへの参照が他にない場合)。

このような小さなクラスを書くことをお勧めします

class T:
    def __del__(self):
        print "deleted"

そして、Pythonインタープリターで調べてください、例えば

>>> a = T()
>>> del a
deleted
>>> a = T()
>>> b = a
>>> del b
>>> del a
deleted
>>> def fn():
...     a = T()
...     print "exiting fn"
...
>>> fn()
exiting fn
deleted
>>>   

jythonとironpythonには、オブジェクトが削除されて__del__呼び出される正確なタイミングに関して異なるルールがあることに注意してください。これと__del__、オブジェクトとその環境が呼び出されたときに不明な状態になる可能性があるため、使用することはお勧めしません。__del__呼び出されることが完全に保証されているわけではありません-インタープリターは、すべてのオブジェクトを削除せずにさまざまな方法で終了できます。


1
stackoverflow.com/a/2452895/611007およびstackoverflow.com/a/1481512/611007と比較すると、use del obj1信頼するのは悪い考えのようです。
n611x007 2013

0

前述したように、__del__機能はある程度信頼できません。役立つと思われる場合は、代わりに__enter__および__exit__メソッドの使用を検討してください。これにより、with open() as f: passファイルへのアクセスに使用される構文と同様の動作が得られます。__enter__範囲に入るときに自動的に呼び出されwithている間、__exit__それを出るときに自動的に呼び出されます。詳細については、この質問を参照してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.