2017-02-06 11 views
3

私は次のコードに関するいくつかのわずか予期しない動作を取得しています:Pythonのクラス変数とインスタンス変数混乱

class MyClass(object): 
    value = 5 

object1 = MyClass() 
object2 = MyClass() 

print object1.value #This displays 5 
print object2.value #This displays 5 
print MyClass.value #This displays 5 

#So far so good 

object1.value = 6 

print object1.value #This displays 6 
print object2.value #This displays 5 
print MyClass.value #This displays 5 

#Still good, but the confusing part is coming up... 

MyClass.value = 10 

print object1.value #This displays 6. I was expecting it to be 10! 
print object2.value #This displays 10 
print MyClass.value #This displays 10 

あなたは、私は変数のインスタンスのバージョンを変更しています見て、期待どおりの結果を得ることができたよう。しかし、私がMyClass.Valueを10に変更すると、ALLインスタンスの値を変更することを期待しています。しかし、おそらく私の理解は正しくないでしょう。

ご協力いただければ幸いです。

答えて

1

最初に、object1object2は、いずれもインスタンス固有の変数を持たないMyClassのインスタンスです。次に、object1.valueを変更します。まだMyClassのメンバーですが、object1.valueを求めるときは、MyClassの値が見れば6になります。これにより、これまで予想されていた動作が得られます。

MyClass.valueを10に変更すると、MyClass.valueを検索すると10が得られます。これは直接検索するか、object2で検索したときに発生します。ただし、object1にはまだvalueが設定されています.を入力するとvalueobject1になり、6が表示されます。MyClassのバージョンが変更されていることがわかりません。

これはobject2には関連付けられていないため、valueは発生しません。検索はobject2で失敗するため、object2.__class__.valueを検索します。 object2object2.__class__MyClassで、MyClassのインスタンスであり、それはあなたがdel object1.valueを言っていた場合は、object1.valueを見上げる10

を与えるので、あなただけのobject2と同じように、MyClassから10を取得したいです。ボンネットの下に何が起こる

0

あなたはインスタンス属性を割り当てるときに、そのインスタンスのプライベート辞書(__dict__)が更新される、ということではなく、クラスの__dict__。前者は要求された属性のルックアップに優先し、見つからない場合(最初の数行では常にobject2)、属性の検索にはクラスの__dict__が使用されます。具体的に

属性の割り当てや削除がインスタンスの辞書、決してクラスの辞書を更新します。クラスに__setattr__()または__delattr__()メソッドがある場合、これはインスタンスディクショナリを直接更新する代わりに呼び出されます。

(重点鉱山the Python documentation on the standard type hierarchy in the data modelから;。あなたは、サブセクション「クラスのインスタンス」、第二段落を見つける必要があります段落を、それはインスタンスを扱う前に、ルックアップ順序を属性全体のサブセクションと1の前に。 、 "カスタムクラス"はコンセプトを得るために読むのが良いかもしれませんが、幾分凝縮されているので、おそらく数回です。)


しばしば私は下に何が起こっているか理解するのに役立ちますどのような、IDおよび()この場合には、関連するインスタンス、クラスと属性の__dict__属性を印刷することです。 IDはあなたが同じオブジェクトを見ていることを本当に保証するものではありませんが、CPythonを使用するときには一般的に私のために働いています。

あなたの本を印刷するように調整コード:

from __future__ import print_function 

class MyClass(object): 
    value = 5 

object1 = MyClass() 
object2 = MyClass() 

print(object1.value, id(object1.value), object1.__dict__) 
print(object2.value, id(object2.value), object2.__dict__) 
print(MyClass.value, id(MyClass.value), MyClass.__dict__) 

object1.value = 6 
print(object1.value, id(object1.value), object1.__dict__) 
print(object2.value, id(object2.value), object2.__dict__) 
print(MyClass.value, id(MyClass.value), MyClass.__dict__) 

MyClass.value = 10 
print(object1.value, id(object1.value), object1.__dict__) 
print(object2.value, id(object2.value), object2.__dict__) 
print(MyClass.value, id(MyClass.value), MyClass.__dict__) 

と(快適さを読み取るための挿入いくつかの余分な改行やスペースを含む)私が手出力:

5 4325640816 {} 
5 4325640816 {} 
5 4325640816 {'__doc__': None, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, 
    '__dict__': <attribute '__dict__' of 'MyClass' objects>, 
    '__module__': '__main__', 'value': 5} 

6 4325640848 {'value': 6} 
5 4325640816 {} 
5 4325640816 {'__doc__': None, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, 
    '__dict__': <attribute '__dict__' of 'MyClass' objects>, 
    '__module__': '__main__', 'value': 5} 

6 4325640848 {'value': 6} 
10 4325640976 {} 
10 4325640976 {'__doc__': None, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, 
    '__dict__': <attribute '__dict__' of 'MyClass' objects>, 
    '__module__': '__main__', 'value': 10} 

IDはごとに変化しますここでは便宜的に'value'は最後にMyClass.__dict__に表示されますが、どの属性が変更され、どれが実質的に同じか、そして__dict__属性がどのように更新されるかを確認できます。

(注:はない一般的に、いずれかから読み取ることがない、どのような方法でそれを使用しないでください__dict__自身の属性変更しない他のビルトインメソッドと関数はそれを扱うみましょう。。)

関連する問題