それが期待されていない場合にpythonで呼び出されるメソッド__del__
-
20-09-2019 - |
質問
私のpythonに新しいですし、Swaroop CHの「パイソンのバイト」の例を挙げて取り組んできました。私は私を不可解さ__del__
方法でいくつかの行動を見ています。
基本的に、私は(Pythonの2.6.2で)次のスクリプトを実行している場合
class Person4:
'''Represents a person'''
population = 0
def __init__(self, name):
'''Initialize the person's data'''
self.name = name
print 'Initializing %s'% self.name
#When the person is created they increase the population
Person4.population += 1
def __del__(self):
'''I am dying'''
print '%s says bye' % self.name
Person4.population -= 1
if Person4.population == 0:
print 'I am the last one'
else:
print 'There are still %d left' % Person4.population
swaroop = Person4('Swaroop')
kaleem = Person4('Kalem')
のPythonコンソール(またはスパイダーインタラクティブコンソール)を使用して、私は次を参照してください。
execfileを(u'C:\ 1_eric \ Pythonの\ test1.py ')
Swaroop
の初期化 初期化Kalemexecfileを(u'C:\ 1_eric \ Pythonの\ test1.py ')
Swaroop
の初期化 Swaroopはさようなら言う
私は最後の1
ています Kalem
の初期化 Kalemはさようなら言う
私は最後の一人です。
なぜセカンドランで__del__
た直後に呼び出される__init__
方法です?
私は、同じインスタンス名(「swaroop」と「kaleem」)ので、それが元のインスタンスを解放して、ゴミがそれを集めることに使用されていることを推測しています。しかし、これは現在の人口数で大混乱を演奏しているようです。
ここで何が起こっている?
混乱のこの種のを避けるための良い方法は何ですか?
__del__
の使用は避けてください?
それらを再利用する前に、既存のインスタンス名を確認しますか?
...
おかげで、 エリック
解決
一般アドバイス:Pythonで__ __デルを使用しないでください。これは、ESP、いくつかの方法でガベージコレクションを破ることができます。オブジェクト間の循環参照の場合
グローバル変数の再定義 - ベストプラクティスではありません -あなたの例では、execfileをの使用()に関連するさまざまな問題があります。あなたは本当に疑似デストラクタ(オブジェクトがガベージコレクトを取得するたびに呼び出されるつまりコード)を作成する必要がある場合はところで、いわゆる「ファイナライザ」関数を書く(それが適切にデストラクタではありません)とweakrefを使用して、それを呼び出します.REFコールバック。それはもちろんのインスタンスメソッドであること、およびコールバックで自己への参照を漏洩しないことを確認し、したがって、ラムダは実際にクロージャを作成することを覚えていないはずです!あなたが破壊されたインスタンスからのデータが必要な場合は、それ以外の場合は動作しません。
、ちょうどラムダ内部の「自己」を参照するの を決して必ず、FUNCのデフォルト引数のアプローチを使用しますfrom weakref import ref
from time import sleep
class Person4:
'''Represents a person'''
population = 0
def __init__(self, name):
'''Initialize the person's data'''
self.name = name
print 'Initializing %s'% self.name
#When the person is created they increase the population
Person4.population += 1
self._wr = ref(self, lambda wr, name=self.name: Person4_finalizer(name))
def Person4_finalizer(name):
'''I am dying'''
print '%s says bye' % name
Person4.population -= 1
if Person4.population == 0:
print 'I am the last one'
else:
print 'There are still %d left' % Person4.population
p1 = Person4("one")
p2 = Person4("two")
p3 = Person4("three")
del p2
del p3
sleep(5)
出力(睡眠は何が起こっているか見るのを助けるためにそこにある):
Initializing one
Initializing two
Initializing three
two says bye
There are still 2 left
three says bye
There are still 1 left
one says bye
I am the last one
他のヒント
ここで起こって物事のカップルがあります。あなたのPerson4
クラスがインスタンス化されると、それはあなたのインタラクティブコンソールから0にそのpopulation
クラス変数を初期化、あなたの「test1.py」ファイルを複数回実行しているように見えます。あなたはそれを実行して二回目は、Person4
クラスは、それが技術的に可能どの再び宣言されているの異なるの最初のもの(それは同じ名前を持つにもかかわらず)から。つまり、独自の独立したpopulation
数を有することを意味する。
さて、swaroop
とkaleem
であるのグローバルの変数、 "test1.py" の両方のあなたのインスタンス間で共有。 Pythonは内部的に自動ガベージコレクションのほとんどのための参照カウントを使用していますので、最初Person4
クラスの元のインスタンスはswaroop
する2番目の割り当てまで解放されません。 swaroop
に割り当てると、参照カウントが現在ゼロであるため__del__
が呼び出される原因と、最初のインスタンスの参照カウントをデクリメントします。 の前ののインスタンスは、それが代わりに古いPerson4
人口数の、の新しいの__del__()
・カウントをデクリメント消える。
Person4
に言及しているので、 >
の意味を作っうまくいけば。これは、Pythonを学ぶ誰かに混乱するかもしれませんなぜ私が見ることができます。 Person4
を使用してexecfile()
クラスを再定義すると同時に、クラス変数の使用はさらに混乱を招く問題です。何が価値があるために、私は、Pythonのコードの多くを書いたと私は私が今まで__del__
特別なメソッドを使用するために必要なてきたとは思わない。