web-dev-qa-db-ja.com

pythonクラスインスタンス変数とクラス変数

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']
29
jonathan topf

これは、Pythonが.で名前を解決する方法が原因です。self.listを書き込むと、Pythonランタイムがlist name最初にインスタンスオブジェクトで検索し、見つからない場合はクラスインスタンスで検索します。

少しずつ見ていきましょう

self.list.append(1)
  1. オブジェクトにlistの名前はありますかself
    • はい:使用してください!終わり。
    • いいえ:2に進みます。
  2. オブジェクトlistのクラスインスタンスにselfの名前がありますか?
    • はい:使用してください!仕上げ
    • いいえ:エラー!

しかし、名前をバインドする場合、状況は異なります。

self.list = []
  1. オブジェクトに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参照を通じて表示されます。

47
rodrigo

Pythonには、名前の検索に関する興味深いルールがあります。あなたが本当にあなたの心を曲げたいのなら、このコードを試してください:

class testClass():
    l = []
    def __init__(self):
        self.l = ['fred']

これにより、各インスタンスにクラス変数lをマスクするlという変数が与えられます。 self.__class__.lを実行すると、クラス変数を取得できます。

私の考えはこれです... instance.variableを実行するときはいつでも(メソッド名であっても、それらはたまたま値である関数である単なる変数です)、インスタンスのディクショナリで調べます。そして、それが見つからない場合は、インスタンスのクラスディクショナリで検索を試みます。これは、変数が「読み取られている」場合のみです。割り当てられている場合は、常にインスタンスディクショナリに新しいエントリが作成されます。

5
Omnifarious

最初の例では、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']
3
Wieland

クラスをインスタンス化すると、__init__メソッドが自動的に実行されます。

最初のケースでは、リストはクラス属性であり、そのすべてのインスタンスによって共有されます。 pをインスタンス化するときに1つ追加し、fをインスタンス化するときにもう1つ追加したため、2つの「もの」が得られました(最初の呼び出しは最初の呼び出しですでに追加されています)。

0
joaquin