2015-12-15 22 views
9

誰かが私に次のコードを説明してください。Pythonでクラスの異なるインスタンスを作成する方法は?

class InnerTest: 

    def __init__(self, value = 0): 
     self.value = value 

class OuterTest: 

    def __init__(self, inner_test = InnerTest()): 
     self.inner_test = inner_test 

a = OuterTest() 
b = OuterTest() 

a.inner_test.value = 42 
print b.inner_test.value 

それは42を出力し、私はInnerTestそれぞれの別個のインスタンスを含むであろうOuterTestの2つのインスタンスを作成することを意味0

を期待。代わりに、InnerTestの同じインスタンスを参照するOuterTestのインスタンスが2つあります。

また、私が欲しいものを実装する正しい方法は何ですか?

答えて

10

関数のデフォルトパラメータは、関数定義時に一度だけ評価されます。したがって、両方のオブジェクトに使用されるインスタンスはInnerTestです。したがって

a = OuterTest() 
b = OuterTest() 

どちらも、a.inner_testb.inner_testは、同じインスタンスを参照している、との結果:意味

は、次の2つのオブジェクトを作成するとき。

は、この問題を解決 Noneにデフォルト値を変更し、条件付きでインスタンスを作成するには:

class OuterTest: 
    def __init__(self, inner_test=None): 
     if not inner_test: 
      inner_test = InnerTest() 
     self.inner_test = inner_test 
+1

@PadraicCunningham必ずしも引数を渡す必要はありません。この場合、 'None'となり、関数内で初期化することができます。 –

+1

@PadraicCunninghamいいえ、問題は同じではありません。値が 'None'であれば、' a'と 'b'の両方で' if'の内部に 'InnerTest'の2つの異なるインスタンスを作成します。 –

+0

これは正解です。何が起きているのかを説明し、デフォルトパラメータの利便性を保ちながら別個のインスタンスを作成する実用的なソリューションを提供します。ありがとう。 – marcv81

2

InnerTest()をinitに移動するか、initで呼び出すことで、2番目のケースのクラスnへの参照を渡すことができます。オブジェクトがINITでそれをインスタンス化することによって、インスタンス属性とは対照的に、それclass attribute製造OuterTestクラスのすべてのインスタンス間で共有されるように、def __init__(self, inner_test = InnerTest()):を使用

が一度評価されます。

class OuterTest: 
    def __init__(self): 
     self.inner_test = InnerTest() 

または:必要に応じて

class OuterTest: 
    def __init__(self, inner_test = InnerTest): 
     self.inner_test = inner_test() 

どちらの方法が動作する、クラスへの参照を渡すと、あなたが好きなクラスを渡すのオプションを持っていることを意味:

In [11]: class OuterTest: 
    ....:  def __init__(self, inner_test=InnerTest): 
    ....:    self.inner_test = inner_test() 
    ....:   

In [12]: a = OuterTest() 

In [13]: b = OuterTest() 

In [14]: a.inner_test.value = 42 

In [15]: print(a.inner_test.value) 
42 

In [16]: print(b.inner_test.value) 
0 

In [17]: class OuterTest: 
    ....:  def __init__(self): 
    ....:    self.inner_test = InnerTest() 
    ....:   

In [18]: a = OuterTest() 

In [19]: b = OuterTest() 

In [20]: a.inner_test.value = 42 

In [21]: print(a.inner_test.value) 
42 

In [22]: print(b.inner_test.value) 
+0

第二の溶液は、私が欲しいものではありませんが、最初のものはうまく動作します。私の元のコードが私がしたいことをしない理由を知りたいですか? – marcv81

+0

inner_textパラメータをオプションにすると、インスタンス化されたオブジェクトをパラメータとして渡すことができます。あなたの答えはうまくいくでしょうか? –

+0

@ marcv81、これは本質的にクラスとインスタンス属性の違いです –

関連する問題