2012-01-14 6 views
6

私は、Pythonがインスタンス変数を処理する方法に奇妙な変わり点があることに気付いたとき、簡単なスクリプトに取り組んでいました。なぜPythonはインスタンス変数をオブジェクト間の共有として扱うのでしょうか?

class Spam(object): 
    eggs = {} 

    def __init__(self, bacon_type): 
     self.eggs["bacon"] = bacon_type 

    def __str__(self): 
     return "My favorite type of bacon is " + self.eggs["bacon"] 

そして、我々は別の引数を持つこのオブジェクトの2つのインスタンスを作成:

spam1 = Spam("Canadian bacon") 
spam2 = Spam("American bacon") 

print spam1 
print spam2 

結果は不可解されています

My favorite type of bacon is American bacon 
My favorite type of bacon is American bacon 

それを

は、我々は単純なオブジェクトを持っていると言います"卵"辞書は、すべての異なる "迷惑メール"インスタンス間で共有されているようです - どちらか、それとも新しいインスタンスが作成されるたびに上書きされます。私たちは、初期化関数でインスタンス変数を宣言することによってそれを解決することができますので、これは、本当に毎日の生活の中で問題ではありません。このように書かれたコードと

class Spam(object): 

    def __init__(self, bacon_type): 
     self.eggs = {} 
     self.eggs["bacon"] = bacon_type 

    def __str__(self): 
     return "My favorite type of bacon is " + self.eggs["bacon"] 

spam1 = Spam("Canadian bacon") 
spam2 = Spam("American bacon") 

print spam1 
print spam2 

、結果は我々が期待するものである。

My favorite type of bacon is Canadian bacon 
My favorite type of bacon is American bacon 

私はこの振る舞いを支持していませんが、なぜPythonがこのように動作するのか理解できません。誰かがこれについていくつかの光を当てることができますか?

+0

[インスタンス間でPythonクラスのデータを共有しないようにするにはどうすればいいですか?](http://stackoverflow.com/questions/1680528/how-do-i-avoid-having-python-class-data-shared -among-instances) –

答えて

7

Ignacioが投稿したように、Pythonのクラススコープに割り当てられた変数はクラス変数です。基本的に、Pythonでは、クラスはclassステートメントのステートメントのリストに過ぎません。その文のリストが実行を終了すると、Pythonはその実行の過程で作成された変数をすべて取り出し、その中からクラスを作り出します。インスタンス変数が必要な場合は、実際にインスタンスに代入する必要があります。

もう1つ注意してください。あなたはJava(Javaのような)パースペクティブから来るかもしれないようです。 Javaでは変数を明示的に宣言する必要があるため、クラススコープでインスタンス変数の宣言を行う必要があります。

class Foo { 
    String bar; 
    public Foo() { 
     this.bar = "xyz"; 
    } 
} 

のみ宣言は、クラススコープであることに留意されたいです。つまり、のメモリはその変数に割り当てられていますが、変数の実際のの値はではありません。

Pythonには変数宣言の必要はありません。だから、Pythonの翻訳では、宣言をドロップするだけです。

class Foo: 
    # String bar; <-- useless declaration is useless 
    def __init__(self): 
     self.bar = "xyz" 

メモリは必要なときに割り当てられます。割り当てだけが実際に書き出されます。そして、それはJavaの場合と同様に、コンストラクタに入ります。

+0

はい、まさに - 私が大学でOOPを取ったときに、私たちはJavaでそれをしました。 –

5

これはインスタンス変数ではなく、それはクラス変数です。インスタンス経由でアクセスされているということは無関係です。それはまだ同じオブジェクトです。

+0

私はあなたが言っていることを得る。しかし、クラスを定義する際に、変数をインスタンス変数またはクラス変数としてどのように宣言しますか?私はあなたがこのコードを見たときにクラス変数であったことをどのように知っていましたか? – Divya

+2

これはクラス定義の一部です。つまり、「Spam.eggs」です。 'self'の属性としてバインドされている場合、それはクラスの属性ではなくインスタンスの属性です。 –

+0

私が正しくあなたを理解していれば、Spamのインスタンスを作成したら、Spam.eggsを直接呼び出して、作成したばかりのSpamインスタンスの卵を入手できますか?ご協力いただきありがとうございます! –

2

Pythonのclass文は実際には実行されるコードであり、メモリにクラスオブジェクト(インスタンスではありません)を作成します。

classブロックの実行時に定義されたシンボルは、クラス自体に属します。これには、最初の例のeggs変数のような変数と、定義した__init__および__str__メソッドが含まれます。それらのすべては、クラスが定義されるときに作成され、それらはすべてクラスの一部です。あなたが実際にオブジェクトのインスタンスを作成するまで

インスタンス変数が作成されていない、と__init__方法が実行され、そして、彼らはselfの属性であることをを持っている。だから、

、Pythonインタプリタは、それが実際に実行時にクラスオブジェクトを構築して

class Spam(object): 
    eggs = {} 

    def __init__(self): 
     <stuff> 
    def __str__(self): 
     <other stuff> 

を実行します。コード "eggs={}"を実行し、2つのdefステートメントを実行し、eggs,__init__および__str__の3つの属性を持つクラスを作成します。その後

、それは

spam1 = Spam() 

を実行すると、新しいインスタンスを作成し、その__init__メソッドを実行します。 __init__メソッド自体はもちろんクラスに属しています。それはeggs属性のように、すべてのインスタンス間で共有されます。

インスタンス自体がselfパラメータとして渡されます。インスタンス上で定義したものは、そのインスタンスだけに属します。そのため、selfをすべてのクラスメソッドに渡す必要があります。つまり、Pythonではメソッドは実際にクラス自体に属し、selfはインスタンスを参照する唯一の方法です。