3

Pythonの初期化がどのように機能するかを理解するために少し助けが必要です。フィールド/変数として別のクラス(Foo)を持つクラス(Bar)があります。この変数を(クラス__init__ではなく)Barで直接初期化しようとすると、Barのすべてのインスタンスが同じFooを指します。ただし、Bar2のように__init__メソッドがある場合、各Bar2インスタンスには一意のFooインスタンスがあります。ここで何が起きてるの?

class Foo():
    number = 0

class Bar():
    foo = Foo()

class Bar2():
    foo = None

    def __init__(self):
        self.foo = Foo()

first = Bar()
second = Bar()

print "Bar"
print first
print second
print first.foo
print second.foo

first = Bar2()
second = Bar2()

print "\nBar2"
print first
print second
print first.foo
print second.foo

たとえば、出力は次のようになります。

Bar
<\__main__.Bar instance at 0x025B2AF8>
<\__main__.Bar instance at 0x025B2B20>
<\__main__.Foo instance at 0x004A3AA8>
<\__main__.Foo instance at 0x004A3AA8>

Bar2
<\__main__.Bar2 instance at 0x025B2B48>
<\__main__.Bar2 instance at 0x025B2AF8>
<\__main__.Foo instance at 0x025B2B70>
<\__main__.Foo instance at 0x025B2B98>

Barを使用すると、両方のインスタンスが同じFooインスタンスを参照します。なんで?

編集:Barに対してfirst.fooを2回印刷する際のエラーを修正しました。結果として生じる動作は、出力に見られるとおりです。

4

4 に答える 4

2

Bar.fooクラス変数です。クラスの作成時に一度初期化されます。

(コードfirst.fooは2回出力されるため、出力が同じであることも不思議ではありません。)

于 2012-09-16T17:36:27.417 に答える
2

Pythonは動的言語です。Javaのような静的言語では、コンパイラはコードを読み取り、クラス定義を見つけて、それらが適切かどうかを判断し、それに応じてコードを生成します。Pythonでは、クラス定義(または関数定義)は、変数への代入のように、他の定義と同じように単なるステートメントです。構文は少し異なります。

クラスを定義するとき、インタプリタはクラス定義を実行します。つまり、クラス行の後にすべてのコードを実行します。関数定義が見つかった場合は、それらも実行します。つまり、関数を定義し、関数名にバインドします。クラスと関数の定義は他の割り当てと同じようにステートメントであるため、多くの場所でそれらを使用することもできます。たとえば、次のようになります。

def foo():
  class A: pass
  a = A()
  a.msg = "Hello"
  return a

Pythonはダックタイプであるため(アヒルのように鳴り、アヒルのように見える場合は1つです)、関数fooのユーザーは、クラスが何と呼ばれるかを知る必要さえありません。fooがオブジェクトを返すことを知っている必要があります。メンバーメッセージ付き。次のように使用します。

a = foo()
print a.msg

したがって、あなたの例では、Barの定義が実行されると、Fooオブジェクトの作成を含むclassesステートメントが実行されます。Bar2の定義が実行されると、クラスステートメントが実行され、その中でinitと呼ばれる関数の定義が実行されます。Pythonは、オブジェクトが作成されたときに呼び出す関数の名前としてこれを使用します(別の関数を呼び出した後です__new__が、それは重要ではありません)。

この場合も、クラス定義(BarがFooオブジェクトを作成するクラス内のコード)は、クラスが導入されたときに1回だけ実行されます。__init__新しいオブジェクトが作成されるたびに何度も呼び出されるため、Bar2ではFooの作成も何度も行われます。

私が知る限り、「foo = None」は不要であり、実際には必要ありません。Pythonでは、クラスの外部からでも、間違いなく内部からでも、どこからでもインスタンス変数を追加できます__init__

于 2012-09-16T19:46:52.210 に答える
1

クラスもオブジェクトであり、独自の変数のセットがあります。それだけでなく、Pythonがオブジェクト内で変数を見つけることができない場合、Pythonはクラス内を調べて、そこで変数を見つけることができるかどうかを確認します。これがPythonが使用するものです。クラスはそのクラスのすべてのオブジェクト間で共有されるため、そのクラス内の変数も共有されます。

于 2012-09-16T17:39:49.103 に答える
0
first = Bar()
second = Bar()

print "Bar"
print first
print second
print first.foo
print first.foo

ここでは、first.fooを2回出力しているため、同じfooオブジェクトが出力されます。

first = Bar2()
second = Bar2()

print "\nBar2"
print first
print second
print first.foo
print second.foo

ここで、fooはクラスBar2の静的変数です。そのため、両方のオブジェクトは、secondの構造で構築された同じfooオブジェクトを指します。

class Bar2():
 foo = None

 def __init__(self):
     self.foo = Foo()

class Bar():
 def __init__(self):
   self.foo = Foo()

Bar2では、Bar2のすべてのオブジェクトは、Bar2の最後に構築されたオブジェクトの構築時に構築された同じオブジェクトを指すfooオブジェクトを持ちます。

Barでは、特に明記されていない限り、すべてのfooオブジェクトはBarのすべてのオブジェクトに対して一意になります。

于 2012-09-16T17:39:10.517 に答える