web-dev-qa-db-ja.com

python=クラスのメンバーとしてリストしますが、そのコンテンツがクラスのすべてのインスタンスで共有されているのはなぜですか?

クラスListenerを定義し、Listenerオブジェクトの辞書を作成しました。各リスナーには、それらを識別するためのidと、リスナーが聞くartistsのリスト_artists = []_があります。 artistsリストに何かを追加すると、参照されたインスタンスではなく、Listenerクラスのすべてのインスタンスに追加されます。これが私の問題です。

リスナークラスは次のように定義されます。

_class Listener:
    id = ""
    artists = []

    def __init__(self, id):
        self.id = id

    def addArtist(self, artist, plays):
        print self.id # debugging...
        print "pre: ", self.artists
        self.artists.append(artist)
        print "post: ", self.artists
_

これが私のデバッグテストコードです:

_def debug():
    listeners = {}
    listeners["0"] = Listener("0")
    listeners["1"] = Listener("1")

    listeners["0"].addArtist("The Beatles", 10)
    listeners["0"].addArtist("Lady Gaga", 4)
    listeners["1"].addArtist("Ace of Base", 5)
_

そして出力:

_0
pre:  []
post:  ['The Beatles']
0
pre:  ['The Beatles']
post:  ['The Beatles', 'Lady Gaga']
1
pre:  ['The Beatles', 'Lady Gaga']
post:  ['The Beatles', 'Lady Gaga', 'Ace of Base']
_

私の期待される出力は、最後のaddArtist("Ace of Base", 5)呼び出しが出力になるということです

_1
pre:  []
post:  ['Ace of Base']
_

これは微妙なPythonわかりませんか?なぜこれが出力であり、代わりにどのようにして希望の出力を得ることができるのですか?ありがとうございます!

24
zebra

メンバーをクラス内で宣言するのではなく、__init__ 方法:

class Listener:
    def __init__(self, id):
        self.id = id
        self.artists = []

    def addArtist(self, artist, plays):
        print self.id # debugging...
        print "pre: ", self.artists
        self.artists.append(artist)
        print "post: ", self.artists

のようなクラスがある場合

class A:
  x=5

その場合、xはクラスのメンバーであり、そのクラスのインスタンスのメンバーではありません。 pythonを使用すると、インスタンスを通じてクラスメンバーにアクセスできるため、これは混乱を招く可能性があります。

>>> a=A()
>>> print a.x
5

ただし、クラス自体からもアクセスできます。

>>> print A.x
5

これは正しく機能しているように見えます:

>>> a1=A()
>>> a2=A()
>>> a1.x=6
>>> print a1.x
6
>>> print a2.x
5

しかし実際に起こったことは、新しいxをa1インスタンスに入れたことです。これは、クラスメンバーの代わりに出力され、元の値を保持しています。

>>> print A.x
5

リストのように変更できるものがある場合にのみ、違いがわかります。

class A:
  l=[]

>>> a1=A()
>>> print a1.l
[]
>>> a2=A()
>>> print a2.l
[]
>>> a1.l.append(5)
>>> print a1.l
[5]
>>> print a2.l
[5]
>>> print A.l
[5]
39
Vaughn Cato

これはPythonの微妙なことですが、理解できませんか?

微妙ではありません。非常に単純です。問題を混乱させる他の言語とは異なり、Pythonでは、クラス内で宣言するすべてがクラスに属します。クラスはオブジェクト(他のすべてと同様)であるため、これは当然のことであり、完全に有効ですしたがって、これらのメソッドはすべて、(何らかの方法で各インスタンスに魔法のようにコピーされるのではなく)クラスに属し、データ属性もそうです。

各リスナーには、それらを識別するためのidがあります

はい、__init__の各インスタンスに1つアタッチするためです。これには何もしないクラスに属するidがあります-インスタンスを介してidを検索するとき、インスタンス自身のidが見つかり、クラスに属するものを非表示にします。

彼らが聴いているアーティストのリスト、アーティスト= []

ただし、クラスを介してartistsを検索すると、インスタンスにクラスがないため、クラスのartistsが見つかります。

アーティストリストに何かを追加すると、リスナークラスのすべてのインスタンスに追加されます

番号; クラス自体にが追加されます。これは、インスタンスに見つからない場合に検索される場所です。

後でインスタンスにself.artists = []のような直接割り当てを行った場合、そのインスタンスはクラスのリストを非表示にする独自のリストを取得することに注意してください。そのコードは他のインスタンスで実行されなかったため、他のインスタンスはそうしませんでした。

2
Karl Knechtel