Pythonでクラス/インスタンス変数がどのように機能するかを理解するのに問題があります。このコードを試してみると、リスト変数がクラス変数のように見える理由がわかりません
class testClass():
list = []
def __init__(self):
self.list.append('thing')
p = testClass()
print p.list
f = testClass()
print f.list
出力:
['thing']
['thing', 'thing']
私がこれをするとき、それはインスタンス変数のようです
class testClass():
def __init__(self):
self.list = []
self.list.append('thing')
p = testClass()
print p.list
f = testClass()
print f.list
出力:
['thing']
['thing']
これは、Pythonが.
で名前を解決する方法が原因です。self.list
を書き込むと、Pythonランタイムがlist
name最初にインスタンスオブジェクトで検索し、見つからない場合はクラスインスタンスで検索します。
少しずつ見ていきましょう
self.list.append(1)
list
の名前はありますかself
?list
のクラスインスタンスにself
の名前がありますか?しかし、名前をバインドする場合、状況は異なります。
self.list = []
list
の名前はありますかself
?したがって、これは常にインスタンス変数です。
最初の例では、クラスインスタンスにlist
を作成します。これは、その時点でアクティブなスコープであるためです(self
はどこにもありません)。ただし、2番目の例では、list
のスコープ内に明示的にself
を作成します。
より興味深いのは例です:
class testClass():
list = ['foo']
def __init__(self):
self.list = []
self.list.append('thing')
x = testClass()
print x.list
print testClass.list
del x.list
print x.list
それは印刷されます:
['thing']
['foo']
['foo']
インスタンス名を削除すると、クラス名はself
参照を通じて表示されます。
Pythonには、名前の検索に関する興味深いルールがあります。あなたが本当にあなたの心を曲げたいのなら、このコードを試してください:
class testClass():
l = []
def __init__(self):
self.l = ['fred']
これにより、各インスタンスにクラス変数l
をマスクするl
という変数が与えられます。 self.__class__.l
を実行すると、クラス変数を取得できます。
私の考えはこれです... instance.variable
を実行するときはいつでも(メソッド名であっても、それらはたまたま値である関数である単なる変数です)、インスタンスのディクショナリで調べます。そして、それが見つからない場合は、インスタンスのクラスディクショナリで検索を試みます。これは、変数が「読み取られている」場合のみです。割り当てられている場合は、常にインスタンスディクショナリに新しいエントリが作成されます。
最初の例では、list
はクラスの属性であり、そのすべてのインスタンスによって共有されています。これは、testClass
タイプのオブジェクトがなくてもアクセスできることを意味します。
>>> class testClass():
... list = []
... def __init__(self):
... self.list.append("thing")
...
>>> testClass.list
[]
>>> testClass.list.append(1)
>>> testClass.list
[1]
ただし、すべてのオブジェクトはlist
属性をクラスと相互に共有します。
>>> testObject = testClass()
>>> testObject.list
[1, 'thing']
>>> testClass.list
[1, 'thing']
>>>
>>> testObject2 = testClass()
>>> testClass.list
[1, 'thing', 'thing']
>>> testObject2.list
[1, 'thing', 'thing']
クラスをインスタンス化すると、__init__
メソッドが自動的に実行されます。
最初のケースでは、リストはクラス属性であり、そのすべてのインスタンスによって共有されます。 p
をインスタンス化するときに1つ追加し、f
をインスタンス化するときにもう1つ追加したため、2つの「もの」が得られました(最初の呼び出しは最初の呼び出しですでに追加されています)。