1

Pythonが次のことを行う理由を誰かが説明できますか?

>>> class Foo(object):
...   bar = []
...
>>> a = Foo()
>>> b = Foo()
>>> a.bar.append(1)
>>> b.bar
[1]
>>> a.bar = 1
>>> a.bar
1
>>> b.bar
[1]
>>> a.bar = []
>>> a.bar
[]
>>> b.bar
[1]
>>> del a.bar
>>> a.bar
[1]

かなり紛らわしいです!

4

6 に答える 6

7

これは、あなたがそれを書いた方法がbar、インスタンス変数ではなくクラス変数であるためです。

インスタンス変数を定義するには、コンストラクターでそれをバインドします。

class Foo(object):
  def __init__(self):
    self.bar = []

これで、クラスではなくFoo( )の単一のインスタンスに属し、割り当てたときに期待する結果が表示されることに注意してください。selfFoo

于 2010-06-15T12:52:15.917 に答える
0

そのようなクラスで要素を宣言すると、その要素はクラスのすべてのインスタンスで共有されます。各インスタンスに属する適切なクラスメンバーを個別に作成するには、次のように__init__で作成します。

class Foo(object):
    def __init__(self):
        self.bar = []
于 2010-06-15T12:53:02.063 に答える
0

最初は、barはクラス変数であり、との間で共有されab両方とも同じオブジェクトa.barを参照します。b.bar

に新しい値を割り当てるとa.bar、これはクラス変数を上書きせず、aオブジェクトに新しいインスタンス変数を追加し、にアクセスするとクラス変数を非表示にしますa.bara.bar(インスタンス変数)を削除するa.barと、クラス変数に再度解決されます。

b.bar一方、常にクラス変数を参照します。オブジェクトの追加やそれに割り当てられた値barの影響を受けません。a

クラス変数を設定するには、クラス自体からアクセスできます。

Foo.bar = 1
于 2010-06-15T12:57:32.983 に答える
0
>>> class Foo(object):
...   bar = []
...

barは共有クラス変数であり、インスタンス変数ではありません。私はそれがあなたの混乱のほとんどを扱っていると信じています。__init__インスタンス変数にするには、他の回答ごとにクラスで定義します。

>>> a = Foo()
>>> b = Foo()
>>> a.bar.append(1)
>>> b.bar
[1]

これがその証拠です。

>>> a.bar = 1
>>> a.bar
1
>>> b.bar
[1]

a.barこれで、インスタンス変数として再定義されました。これは、デフォルトで変数を外部で定義するときに起こることです。

>>> a.bar = []
>>> a.bar
[]
>>> b.bar
[1]
>>> del a.bar
>>> a.bar
[1]

また同じ。b.barはまだ共有クラス変数です。

于 2010-06-15T13:00:00.933 に答える
0

他の人が言っているように、書かれたコードはインスタンス変数ではなくクラス変数を作成します。__init__インスタンス変数を作成するには、を割り当てる必要があります。

うまくいけば、この注釈付きのコードのコピーが、各段階で何が起こっているのかを説明するのに役立つでしょう。

>>> class Foo(object):
...   bar = []          # defines a class variable on Foo (shared by all instances)
...
>>> a = Foo()
>>> b = Foo()
>>> a.bar.append(1)     # appends the value 1 to the previously empty list Foo.bar
>>> b.bar               # returns the value of the class variable Foo.bar
[1]
>>> a.bar = 1           # binds 1 to the instance variable a.bar, masking the access
>>> a.bar               # you previously had to the class variable through a.bar
1
>>> b.bar               # b doesn't have an instance variable 'bar' so this still
[1]                     # returns the class variable
>>> a.bar = []          # bind a's instance variable to to an empty list
>>> a.bar
[]
>>> b.bar               # b doesn't have an instance variable 'bar' so this still
[1]                     # returns the class variable
>>> del a.bar           # unbinds a's instance variable unmasking the class variable
>>> a.bar               # so a.bar now returns the list with 1 in it.
[1]

また、Foo.bar各ステートメントの後に(インスタンスではなくクラスを介してアクセスされるクラス変数)の値を出力すると、何が起こっているのかを明確にするのに役立つ場合があります。

于 2010-06-15T13:09:12.173 に答える
0

関連する注意事項として、近いうちに見られる可能性のあるこの落とし穴に注意する必要があります。

class A:
   def __init__(self, mylist = []):
      self.mylist = mylist


a = A()
a2 = A()

a.mylist.append(3)
print b.mylist #prints [3] ???

これは多くの人々を混乱させ、コードがどのように解釈されるかに関係しています。Pythonは実際には最初に関数の見出しを解釈するため、__init__(self, mylist = [])そのリストへの参照をデフォルトのパラメーターとして評価して保存します。つまり、Aのすべてのインスタンスは(独自のリストが提供されていない限り)元のリストを参照します。そのようなことをするための正しいコードは

class A:
   def __init__(self, mylist=None):
      if mylist:
         self.mylist = mylist
      else:
         self.mylist = []

または、より短い式が必要な場合は、3項構文を使用できます。

self.mylist = mylist if mylist else []
于 2010-06-15T13:14:25.487 に答える