7

私は Python を初めて使用し、Swaroop CH の「A Byte of Python」の例に取り組んできました。私を__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 コンソール (または Spyder インタラクティブ コンソール) を使用すると、次のように表示されます。

execfile(u'C:\1_eric\Python\test1.py')
Swaroopの
初期化 Kalem の初期化

execfile(u'C:\1_eric\Python\test1.py') Swaroop を
初期化 して い ます




2 回目の実行の__del__直後にメソッドが呼び出されるのはなぜですか? 同じインスタンス名 (「swaroop」と「kaleem」) が使用されているため、元のインスタンスを解放し、それをガベージ コレクションしていると推測しています。しかし、これは現在の人口数に大混乱を引き起こしているようです。 __init__

ここで何が起こっているのですか?
この種の混乱を避ける良い方法は何ですか? ?
の使用は避けてください。__del__再利用する前に既存のインスタンス名を確認しますか? ...

ありがとう、エリック

4

2 に答える 2

19

ここでいくつかのことが起こっています。Person4クラスがインスタンス化されると、そのクラス変数が 0 に初期化されますpopulation。インタラクティブ コンソールから、「test1.py」ファイルを複数回実行しているように見えます。2 回目に実行すると、Person4クラスが再度宣言されるため、最初のクラスとは技術的に異なります (同じ名前であっても)。つまり、独自の独立したpopulationカウントがあります。

swaroopとは、「 test1.py 」の両方のインスタンス間で共有さkaleemれるグローバル変数です。Python は、その自動ガベージ コレクションのほとんどで内部的に参照カウントを使用しているため、最初のPerson4クラスの元のインスタンスは への 2 番目の割り当てまで解放されませんswaroop。に割り当てるとswaroop、最初のインスタンスの参照カウントが減少し、__del__参照カウントがゼロになったため、 が呼び出されます。しかし、Person4内部__del__()で名前で参照しているため、のインスタンスが消えると、古い人口数ではなく、新しい数が減少します。 Person4.populationPerson4

うまくいけば、それは理にかなっています。これが Python を学んでいる人にとって混乱を招く理由がわかります。Person4を使用してクラスを再定義すると同時にクラス変数を使用するexecfile()と、さらに混乱します。__del__それだけの価値はありますが、私は多くの Python コードを書いてきましたが、特別なメソッドを使用する必要があったとは思いません。

于 2009-12-20T07:54:26.873 に答える
7

一般的なアドバイス: Python では __ del __ を使用しないでください。ガベージコレクションをさまざまな方法で壊す可能性があります。オブジェクト間の循環参照の場合。

あなたの例では、ベストプラクティスではない execfile() の使用とグローバル変数の再定義に関連するさまざまな問題があります。ところで、疑似デストラクタ (つまり、オブジェクトがガベージ コレクションされるたびに呼び出されるコード) を本当に作成する必要がある場合は、いわゆる「ファイナライザ」関数 (適切なデストラクタではありません) を作成し、weakref を使用して呼び出します。 .ref コールバック。もちろん、これはインスタンス メソッドであってはなりません。ラムダは実際にクロージャーを作成することを覚えておいてください。したがって、コールバックで self への参照をリークしないようにしてください。破棄されたインスタンスからのデータが必要な場合は、func の既定の引数アプローチを使用します。ただし、ラムダ内で「self」を参照しないようにしてください。そうしないと機能しません。

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
于 2009-12-20T11:26:30.173 に答える