2012-03-17 11 views
12

He definido una clase Listener y he creado un diccionario de objetos Listener. Cada oyente tiene un id para identificarlos, y una lista de artists que escuchan, artists = []. Agregar algo a la lista artists lo agrega para todas las instancias de la clase Listener, en lugar de la instancia referida. Este es mi problema.Lista como miembro de una clase python, ¿por qué se comparte su contenido en todas las instancias de la clase?

La clase de detector se define de la siguiente manera:

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 

Aquí es mi depuración de código de prueba:

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) 

Y la salida:

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'] 

Mi resultado esperado es que el la llamada final addArtist("Ace of Base", 5) daría como resultado la salida

1 
pre: [] 
post: ['Ace of Base'] 

¿Es esta una sutileza de Python que no entiendo? ¿Por qué es este el resultado y cómo puedo obtener el resultado deseado en su lugar? ¡Gracias!

Respuesta

24

Usted no quiere que los miembros declaran dentro de la clase, pero apenas se fija en el __init__ método:

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 

Si usted tiene una clase como

class A: 
    x=5 

entonces x es un miembro de la clase y no un miembro de las instancias de esa clase. Esto puede ser confuso, ya que Python le permite acceder a miembros de la clase a través de la instancia:

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

Pero también se puede acceder a él a través de la propia clase:

>>> print A.x 
5 

Parecería incluso que esto funciona correctamente:

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

pero lo que realmente ha sucedido es que se ha puesto un nuevo X en el ejemplo A1, que se van a imprimir en lugar del miembro de la clase, que todavía tiene su valor original:

>>> print A.x 
5 

Sólo empezar a ver una diferencia cuando se tiene algo que se puede cambiar, como una lista:

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] 
4

¿Es esta una sutileza de Python que no estoy entendiendo?

No es sutil, es bastante simple; a diferencia de otros idiomas que confunden el problema, en Python todo lo que declaras dentro de la clase pertenece a la clase. Esto es natural, ya que las clases son objetos (como todo lo demás), y por lo tanto un lugar perfectamente válido para adjuntar cosas. Por lo tanto, todos esos métodos pertenecen a la clase (en lugar de ser mágicamente copiados de alguna manera a cada instancia), y también lo hacen los atributos de los datos.

Cada oyente tiene un id identificarlos

Sí, porque usted añade uno a cada instancia en el __init__. Esto tiene nada que ver conid que pertenece a la clase, excepto que cuando busca id a través de una instancia, se encontrará el propio id de la instancia, ocultando el que pertenece a la clase.

y una lista de artistas que escuchan, artistas = []

Cuando miras artists través de la clase, sin embargo, se encontró la clase artists, porque la instancia no lo hace Toma uno.

añadir algo a la lista de artistas que se suma para todas las instancias de la clase Listener

n; se ha agregado a la propia clase, que es donde se buscan las cosas cuando no se encuentran en la instancia.

Tenga en cuenta que si realizó una asignación directa como self.artists = [] en una instancia posterior, esa instancia obtendría su propia lista que oculta la lista de la clase. Otras instancias no lo harían, porque ese código no se ejecutó en las otras instancias.

Cuestiones relacionadas