5

好奇心が強いオブジェクトで明示的に呼び出されているコードを見た__del__ので、それがどのように機能するかを理解するために少し遊んでみました。

私は次のコードを試しました(使用__del__すること自体が悪い可能性があることは理解していますが、ここで自分自身を教育しようとしているだけです):

class A:
    def __init__(self, b):
        self.a = 123
        self.b = b
        print "a is {}".format(self.a)
    def __del__(self):
        self.a = -1
        print "a is {}".format(self.a)
        self.b.dont_gc_me = self
    def foo(self):
        self.a = 9999999
        print "a is {}".format(self.a)

class Foo:
    def __init__(self):
        self.a = 800
    def __del__(self):
        self.a = 0

次に、(IPythonコンソールで)次のことを試しました:

In [92]: f = Foo()

In [93]: a = A(f)
a is 123

In [94]: a = None
a is -1

In [95]: f.__dict__
Out[95]: {'a': 800, 'dont_gc_me': <__main__.A instance at 0x2456830>}

In [96]: f = None

In [97]: 

インスタンス aがインスタンス f によって維持されていて__del__も、それが一度だけ呼び出されることがわかります。後者を に設定すると、デストラクタが 2 回目に呼び出されることはありません。AFooNone

ここのPythonドキュメントには次のように書かれています:

__del__() インスタンスへの新しい参照を作成することにより、メソッドがインスタンスの破棄を延期する可能性があることに注意してください (お勧めしませんが!) 。その後、この新しい参照が削除されたときに呼び出される場合があります。__del__()インタープリターが終了したときにまだ存在しているオブジェクトに対してメソッドが呼び出されることは保証されていません。

これは、メソッドが再度呼び出される可能性があることを暗示しているようです__del__が、そうなる保証はありません。__del__だから私の質問は次のとおりです。再び呼び出される状況はありますか? (上記に設定fするNoneとうまくいくと思いましたが、そうではありませんでした)。注目に値する他のニュアンスはありますか?

4

3 に答える 3

1

__del__循環ガベージ コレクタによって収集されるオブジェクトに対して呼び出されることはありません。

最初の呼び出しで__del__はサイクルを作成しているため、循環コレクターに依存してクリーンアップすることになります

__del__再度呼び出すことができる唯一の方法は、循環参照を手動で解除する場合です

于 2013-09-24T01:21:15.353 に答える
0

ティムの答えは信頼できるものです。オブジェクトの復活__del__()により、ファイナライザーまたはその他 (finallyジェネレーター関数の句など) を任意の頻度で呼び出すことができます。これは実装とバージョンに依存します。ただし、CPython 3.4 からは、PEP 442 -- Safe object finalization 、Java のようにAntoine Pitrouのおかげで、ファイナライザーは 1 回だけ呼び出されます。

ただし、これは Pythonic の例が必要です。ここに1つあります:

import sys
cart = []
class PlagueVictim:
    RETORTS = ("I'm not dead.",
               "I'm getting better.",
               'I feel fine.',
               "I think I'll go for a walk.",
               'I feel happy. I feel happy.')
    DEFAULT_RETORT = "I'm still not dead."
    @classmethod
    def retort(cls, i):
        try: return cls.RETORTS[i]
        except IndexError: return cls.DEFAULT_RETORT
    def __init__(self): self.incarnation = 0
    def __del__(self):
        print(self.retort(self.incarnation))
        if cart is not None: cart.append(self)
        self.incarnation += 1

cart.append(PlagueVictim())
print("> Here's one.")
cart.pop() and None
if not cart: sys.exit()

print(">> 'ere, he says he's not dead.")
# Stubborn, aren't you?
cart.pop() and None
cart.pop() and None
cart.pop() and None
cart.pop() and None
del PlagueVictim.__del__
print('*thwack*')
cart.pop() and None
print('>> Ah, thank you very much.')
print(len(cart))

注意深い読者Noneは、モジュール グローバルがNoneCPython <3.4 (Issue18214) でシャットダウン時に設定れ、改善されたファイナライズに続いて修正されたため、チェックに注意するでしょうand None_) 対話モードで。

于 2014-04-24T13:45:47.390 に答える