2012-06-03 21 views
5

これは、参照カウントがPythonでどのように機能するかをよりよく理解するための試みです。クラス変数の参照カウントを理解する

クラスを作成してインスタンス化しましょう。 (それは独自の内部構造が1で参照カウントを増やし、そのクラスのインスタンスを参照しますので、getrefcountディスプレイ2)インスタンスの参照カウントは1次のようになります。

>>> grc(a.x) 
3 

>>> from sys import getrefcount as grc 
>>> class A(): 
    def __init__(self): 
     self.x = 100000 


>>> a = A() 
>>> grc(a) 
2 

aの内部変数x2の参照を持っています

私はそれがaA__init__メソッドによって参照されることを期待しました。それから私はチェックすることにしました。

変数xにアクセスできるように、名前空間に一時変数bを作成しました。それは3になることは(予想通り)1によりREF-数を増加:

>>> b = a.x 
>>> grc(a.x) 
4 

その後、私はクラスのインスタンスと1減少参照カウントを削除:

>>> del a 
>>> grc(b) 
3 

だから今があります2参照:1つはbであり、1つはAである(予想通り)。

A__main__から削除すると、私はカウントが再び1で減少すると予想しています。

>>> del A 
>>> grc(b) 
3 

しかし、それは起こりません。 Aクラスまたは100000を参照する可能性のあるインスタンスはありませんが、それでも以外の__main__名前空間によって参照されています。

私の質問は、100000とは何ですか?bから離れていますか?


BrenBarnは、私が代わりにどこかに内部的に保存することができる数のobject()を使用する必要があることを示唆しました。非常に論理的であるbによって唯一つの基準があったインスタンスaを削除した後

>>> class A(): 
    def __init__(self): 
     self.x = object() 


>>> a = A() 
>>> b = a.x 
>>> grc(a.x) 
3 
>>> del a 
>>> grc(b) 
2 

数字が100000のようになっていない理由は、理解しておく必要があることだけです。

+0

私の推測は、 'A .__ dict__'ですか? –

+0

@JakobBowyerしかし、私が 'A'を削除すると、' A .__ dict__'は(私が理解するように)何も参照されていないのでガベージコレクションされるべきです。 – ovgolovin

+1

この回答を見る:http://stackoverflow.com/questions/759740/unexpected-result-from-sys-getrefcount –

答えて

2

a.xは整数10000です。__init__()のメソッドAに対応するコードオブジェクトによってこの定数が参照されます。

del A 

は名前だけAを削除し、Aの参照カウントを減少させる

>>> def f(): return 10000 
>>> f.__code__.co_consts 
(None, 10000) 

ライン:コードオブジェクトは、常に、コード内のすべてのリテラルの定数への参照が含まれています。 Python 3.x(ただし2.xではなく)では、クラスには循環参照が含まれることが多く、明示的にガベージコレクタを実行したときにのみガベージコレクションされます。そして実際、bの参照カウントの削減につながるんdel A

import gc 
gc.collect() 

を使用。

+0

'A'を削除して、' A'によってのみ参照される '__init__'を削除しないようにするべきです(私が理解するように)? – ovgolovin

+0

ああ。私は今参照してください。 '__main__'から削除する前に' A'の参照カウントは '4'です。したがって、この削除は '1'だけ減らします。 'A 'を参照する他のオブジェクトは何ですか? – ovgolovin

+0

@ovgolovin:私はあなたの結果を再現できないことに気がつきました。私にとっては、クラスAは実際には*削除され、bのリファレンスカウントは減少します*。私が考えることができる唯一の他のもの:インタラクティブなインタプリタの '_ 'に注意してください。疑わしいときは、インタラクティブなインタプリタではなく、スクリプトで参照カウントを使った実験を行う方がよいでしょう。 –

2

これは、テスト値として整数を使用する場合の成果物である可能性があります。 Pythonは、後で再利用するために整数オブジェクトを格納することがあります。代わりにself.x = object()を使用してコードを実行すると(これは常にxの新しいオブジェクトを作成します)、最後にgrc(b)==2を取得します。

+0

あなたは正しいです! '100000'を' object() 'に変更すると、' getrefcount'に返された数字が変更されました。私は質問を更新します。 – ovgolovin

+0

@ovgolovin:コードオブジェクトはコード内に現れる*定数のみを参照できるため、もちろんです。しかし、これは整数オブジェクトの再利用とは全く関係ありません。整数は、後で再利用するためにランダムにキャッシュされません。 Pythonは、インタープリタの開始時に作成され、必要に応じて使用される小さな整数のキャッシュ(通常は-5〜256)しか保持しません。他のすべての整数は必要に応じて作成され、再利用されることはありません。 –

+0

下降:観測結果は正確ですが、この回答の理由は間違っています。 –

関連する問題