2012-01-02 17 views
26

クラス/インスタンス変数がどのように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'] 

の多くのおかげ

JON

+1

私が正しく理解していれば、Pythonの構文に関する特定の設計上の意思決定の根拠を求めています。そのような質問の場合、最善の答えは「それが言語の精神に合っている」か、もっと賢明に「創造者に尋ねる」ことです。 – Xion

+0

OK変数はデフォルトでクラス変数で、私の混乱の原因となっていたはずです。私の質問だったはずです。変数はデフォルトでクラス変数になります。 –

+4

@jonathantopfいいえ、変数はデフォルトではクラス変数ではありません。 Pythonでは、varablesを宣言しません。その点に関しては、実際には変数ではありません(Pythonは_variableless_lanuageです)。名前だけです。そして、あなたは宣言したり、名前をつけたりすることはありません。あなたはそれらをオブジェクトにバインドします。また、実行時の各オブジェクトには、名前からオブジェクトへの辞書があります。 2つのオブジェクトが同じクラスのものであっても、非常に異なる辞書を持つことができます。 – rodrigo

答えて

40

これは、Pythonが.と名を解決する方法のためです。 self.listと書くと、Pythonランタイムはlistという名前をまずインスタンスオブジェクトで探し、クラスインスタンスに見つからない場合に名前を解決しようとします。

のステップ

self.list.append(1) 
  1. バイステップでそれに見てみましょうオブジェクトselflist名前はありますか?
    • はい:これを使用してください。完了。
    • 番号:2
  2. に行くオブジェクトselfのクラスのインスタンスへのlist名前はありますか?
    • はい:これを使用してください。フィニッシュ
    • いいえ:エラー!

しかし、あなたが名前をバインドするとき、物事は異なっている:

self.list = [] 
  1. は、オブジェクトselflist名前はありますか?
    • はい:上書きしてください!
    • いいえ:バインドしてください!

これは常にインスタンス変数です。

最初の例では、listがクラスインスタンスに作成されます。これは、その時点のアクティブスコープであるため(どこでもselfはありません)。しかし、2番目の例では、selfの範囲に明示的にlistを作成しています。

さらに興味深いのは、たとえば次のようになります。

出力します
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参照を通じて表示されているインスタンス名を削除した瞬間。

+0

私はちょうど__init__の外で 'self.list []'を実行しようとしましたが、これは意味がありますが、方法はありますか? –

+0

@jonathantopf:インスタンス変数は、インスタンスがあるときにのみ作成できます。インスタンス化されたメソッドで作成する必要があります。他のオプションは '__new__'をオーバーロードしてそこに作成することですが、' __new__'が本当に必要なものではないので、実際には醜いですし、 '__init__'で作成するよりもそれほど良い方法ではありません。何を祈って、あなたはこの能力が必要だと思いますか? '__new__'をオーバーロードしてクラスのdictを見て、インスタンスdictに物をコピーするメタクラスを作成することができます。しかし、それは本当に**醜いです。 – Omnifarious

+0

:)ポイントを取った、それは意味がある、私はそれのような質問をするのは嫌いだが、時には、私の知っている私は知っているかどうか、私は思考何が思考ですか? –

0

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

リストはクラス属性であり、すべてのインスタンスで共有されます。 pをインスタンシエートするときに追加したものとfをインスタンシエートするときに追加したものの2つのものがあります(最初の呼び出しで最初にすでに追加されています)。

3

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

Pythonが探しについての興味深いルールを持っています名前をアップ。あなたが本当にあなたの心を曲げるようにしたい場合は、このコードを試してみてください。

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

これは、各インスタンスにlそのマスククラス変数lという変数を提供します。 self.__class__.lを実行すると、クラス変数を取得することはできます。

私はそれを考えています...いつでもあなたはinstance.variable(メソッド名でさえ、それらは値が関数になる変数です)インスタンスの辞書でそれを探します。それが見つからなければ、インスタンスのクラスの辞書でそれを探します。変数が '読み込み中'の場合のみです。に割り当てられている場合、常にインスタンス辞書に新しい項目が作成されます。

+0

どのような厄介な合併症!この回答は本当に役に立ちました。なぜなら、「読み書き」のケースが私に頭痛を与えていたからです。 – dotslash

関連する問題