2008-12-07 27 views
59

Estoy tratando de crear un script de Python que abra varias bases de datos y compare sus contenidos. En el proceso de creación de ese script, me he encontrado con un problema al crear una lista cuyos contenidos son objetos que he creado.Crear una lista de objetos en Python

He simplificado el programa hasta el mínimo de esta publicación. Primero creo una nueva clase, creo una nueva instancia de la misma, le asigno un atributo y luego lo escribo en una lista. Luego asigno un nuevo valor a la instancia y lo vuelvo a escribir en una lista ... y una y otra vez ...

El problema es que siempre es el mismo objeto, así que realmente solo estoy cambiando el objeto base. Cuando leo la lista, obtengo una repetición del mismo objeto una y otra vez.

Entonces, ¿cómo se escriben objetos en una lista dentro de un bucle?

Aquí está mi código simplificado

class SimpleClass(object): 
    pass 

x = SimpleClass 
# Then create an empty list 
simpleList = [] 
#Then loop through from 0 to 3 adding an attribute to the instance 'x' of SimpleClass 
for count in range(0,4):  
    # each iteration creates a slightly different attribute value, and then prints it to 
# prove that step is working 
# but the problem is, I'm always updating a reference to 'x' and what I want to add to 
# simplelist is a new instance of x that contains the updated attribute 

x.attr1= '*Bob* '* count 
print "Loop Count: %s Attribute Value %s" % (count, x.attr1) 
simpleList.append(x) 

print '-'*20 
# And here I print out each instance of the object stored in the list 'simpleList' 
# and the problem surfaces. Every element of 'simpleList' contains the same  attribute value 

y = SimpleClass 
print "Reading the attributes from the objects in the list" 
for count in range(0,4): 
    y = simpleList[count] 
    print y.attr1 

Entonces, ¿cómo (se añade, extiendo, copiar o lo que sea) los elementos de SimpleList de modo que cada entrada contiene una instancia diferente del objeto en lugar de todos apuntando a la misma ¿uno?

+1

le sugiero que utilice iteradores en lugar de contadores: "para el artículo en simpleList:" se ve mucho mejor. – Mapad

Respuesta

5

Crea una nueva instancia cada vez, donde cada instancia nueva tiene el estado correcto, en lugar de modificar continuamente el estado de la misma instancia.

De forma alternativa, almacene una copia explícita del objeto (usando la sugerencia at this page) en cada paso, en lugar de en el original.

+1

+1: Nunca vuelva a utilizar un objeto; crea uno nuevo ¡Son baratos! –

53

Usted demuestra un malentendido fundamental.

Nunca ha creado ninguna instancia de SimpleClass, porque no la ha llamado.

for count in xrange(4): 
    x = SimpleClass() 
    x.attr = count 
    simplelist.append(x) 

O bien, si permite que la clase tome parámetros, en su lugar, puede utilizar una lista de comprensión.

simplelist = [SimpleClass(count) for count in xrange(4)] 
3

Si entiendo correctamente su pregunta, usted pregunta cómo ejecutar una copia profunda de un objeto. ¿Qué hay de usar copy.deepcopy?

import copy 

x = SimpleClass() 

for count in range(0,4): 
    y = copy.deepcopy(x) 
    (...) 
    y.attr1= '*Bob* '* count 

Una copia profunda es una copia recursiva de todo el objeto. Para obtener más referencias, puede echar un vistazo a la documentación de python: https://docs.python.org/2/library/copy.html

+2

Reutilizar un objeto - copia profunda o clonar - es una confusión n00b común. Algunas veces no puedes responder la pregunta que parece hacer; a veces tienes que responder la pregunta que deberían haber hecho. –

8

No debería ser necesario volver a crear el objeto SimpleClass cada vez, como sugieren algunos, si simplemente lo está utilizando para generar datos basados ​​en sus atributos Sin embargo, en realidad no está creando una instancia de la clase; simplemente está creando una referencia al objeto de la clase en sí. Por lo tanto, agrega una referencia al mismo atributo de clase a la lista (en lugar del atributo de instancia), una y otra vez.

En lugar de:

x = SimpleClass 

que necesita:

x = SimpleClass() 
+5

'x = SimpleClass()' _is_ recrea el objeto todo el tiempo. – neil

45

Para rellenar una lista con las instancias separadas de una clase, se puede utilizar un bucle en la declaración de la lista. El * multiplicar vinculará cada copia a la misma instancia.

instancelist = [ MyClass() for i in range(29)] 

y luego acceder a las instancias a través del índice de la lista.

instancelist[5].attr1 = 'whamma' 
+0

mejor sea: instancelist = [MyClass() para _ en rango (29)] – shorttermmem

0

Creo que esto simplemente demuestra lo que está tratando de lograr:

# coding: utf-8 

class Class(): 
    count = 0 
    names = [] 

    def __init__(self,name): 
     self.number = Class.count 
     self.name = name 
     Class.count += 1 
     Class.names.append(name) 

l=[] 
l.append(Class("uno")) 
l.append(Class("duo")) 
print l 
print l[0].number, l[0].name 
print l[1].number, l[1].name 
print Class.count, Class.names 

ejecutar el código anterior y se obtiene: -

[<__main__.Class instance at 0x6311b2c>, 
<__main__.Class instance at 0x63117ec>] 
0 uno 
1 duo 
2 ['uno', 'duo'] 
Cuestiones relacionadas