3

オブジェクトの削除が Python でどのように機能するかを理解したいと思います。これは非常に単純なコードの集まりです。

class A(object):

    def __init__(self):
        setattr(self, "test", self._test)

    def _test(self):
        print "Hello, World!"

    def __del__(self):
        print "I'm dying!"

class B(object):

    def test(self):
        print "Hello, World!"

    def __del__(self):
        print "I'm dying"

print "----------Test on A"
A().test()
print "----------Test on B"
B().test()

Pythonista は、Python 2.x バージョンを実行していることを認識します。さらに具体的には、このコードは python 2.7.1 セットアップで実行されます。

このコードは次を出力します。

----------Test on A
Hello, World!
----------Test on B
Hello, World!
I'm dying

驚いたことに、Aオブジェクトは削除されません。setattrのステートメントは__init__循環参照を生成するため、その理由は理解できます。しかし、これは簡単に解決できそうです。

最後に、Python ドキュメント (Supporting Cyclic Garbage Collection)のこのページは、この種の循環参照を処理できることを示しています。

私が知りたいのですが:

  • クラス__del__でメソッドを実行しないのはなぜですか?A
  • 循環参照に関する私の診断が正しい場合、objectサブクラスが循環ガベージ コレクションをサポートしていないのはなぜですか?
  • 最後に、本当に行きたいsetattr場合、この種の対処方法は?__del__

注:がモジュールの別のメソッドを指しているA場合、問題はありません。setattr

4

2 に答える 2

1

事実1

通常、インスタンス メソッドはクラスに格納されます。インタープリターは、最初にインスタンスでそれらを検索します__dict__が、これは失敗し、次にクラスを検索しますが、成功します。

Ainのインスタンス メソッドを動的に設定する場合__init__は、インスタンス ディクショナリでそのメソッドへの参照を作成します。この参照は循環的であるため、refcount がゼロになることはなく、参照カウンターはクリーンAアップされません。

>>> class A(object):
...     def _test(self): pass
...     def __init__(self):
...             self.test = self._test
... 
>>> a = A()
>>> a.__dict__['test'].im_self

事実2

ガベージ コレクターは、Python が循環参照を処理するために使用するものです。残念ながら、__del__メソッドを含むオブジェクトを処理することはできません。一般に、オブジェクトを呼び出す安全な順序を判断できないためです。代わりに、そのようなオブジェクトをすべて に入れるだけですgc.garbage。次に、そこに行ってサイクルを壊し、解放できるようにします。ドキュメントから

gc.garbage

コレクターが到達不能であることが判明したが、解放できなかったオブジェクト (収集不能オブジェクト) のリスト。デフォルトでは、このリストには__del__()メソッドを持つオブジェクトのみが含まれます。メソッドを持ち__del__()、参照サイクルの一部であるオブジェクトは、必ずしもサイクル内にあるとは限らないがそこからのみ到達可能なオブジェクトを含め、参照サイクル全体を収集不能にします。Python は、このようなサイクルを自動的に収集しません。一般に、Python が実行する安全な順序を推測することができないためです。__del__()メソッド。安全な順序がわかっている場合は、ガベージ リストを調べて、リスト内のオブジェクトが原因で循環を明示的に中断することで、強制的に問題を解決できます。これらのオブジェクトは、ガベージ リストに含まれているため、有効に保たれているため、ガベージからも削除する必要があることに注意してください。たとえば、サイクルを壊した後del gc.garbage[:]、リストを空にします。通常は、__del__()メソッドを持つオブジェクトを含むサイクルを作成しないことで問題を回避することをお勧めしますgarbage。その場合は、そのようなサイクルが作成されていないことを確認するために調べることができます。

したがって

__del__オブジェクトをガベージ コレクトしたい場合は、メソッドを持つオブジェクトに対して循環参照を作成しないでください。

于 2012-03-22T17:50:06.257 に答える
0

メソッドに関するドキュメントを__del__かなり注意深く読む必要があります。具体的には、メソッドを持つオブジェクト__del__がコレクターの動作方法を変更する部分です。

gc モジュールは、これを自分でクリーンアップできるいくつかのフックを提供します。

ここにメソッドがないだけ__del__で、オブジェクトが適切にクリーンアップされると思います。gc.garbageのインスタンスが存在するかどうかを調べて確認することで、これを確認できますA

于 2012-03-22T17:39:54.443 に答える