Estoy intentando crear un script de Python que abra varias bases de datos y compare su contenido. En el proceso de crear ese script, me encontré con un problema al crear una lista cuyo contenido son objetos que he creado.
He simplificado el programa al mínimo para esta publicación. Primero creo una nueva clase, creo una nueva instancia de ella, le asigno un atributo y luego lo escribo en una lista. Luego asigno un nuevo valor a la instancia y nuevamente lo escribo en una lista ... y una y otra vez ...
El problema es que siempre es el mismo objeto, así que en realidad 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 puedo (agregar, extender, copiar o lo que sea) los elementos de simpleList para que cada entrada contenga una instancia diferente del objeto en lugar de que todos apunten al mismo?
Respuestas:
Demuestra un malentendido fundamental.
Nunca creó una instancia de SimpleClass en absoluto, porque no la llamó.
for count in xrange(4): x = SimpleClass() x.attr = count simplelist.append(x)
O, si deja que la clase tome parámetros, en su lugar, puede usar una lista de comprensión.
simplelist = [SimpleClass(count) for count in xrange(4)]
fuente
Para llenar una lista con instancias separadas de una clase, puede usar un bucle for en la declaración de la lista. El * multiplica 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'
fuente
No debería ser necesario volver a crear el objeto SimpleClass cada vez, como algunos sugieren, si simplemente lo está utilizando para generar datos en función de sus atributos. Sin embargo, en realidad no está creando una instancia de la clase; simplemente está creando una referencia al objeto de clase en sí. Por lo tanto, está agregando una referencia al mismo atributo de clase a la lista (en lugar del atributo de instancia), una y otra vez.
En vez de:
necesitas:
fuente
x = SimpleClass()
está recreando el objeto cada vez.Cree una nueva instancia cada vez, donde cada nueva instancia tenga el estado correcto, en lugar de modificar continuamente el estado de la misma instancia.
Alternativamente, almacene una copia hecha explícitamente del objeto (usando la sugerencia en esta página ) en cada paso, en lugar del original.
fuente
Si entiendo correctamente tu pregunta, me preguntas una forma de ejecutar una copia profunda de un objeto. ¿Qué pasa con el uso de 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 información, puede consultar la documentación de Python: https://docs.python.org/2/library/copy.html
fuente
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
Ejecute el código anterior y obtendrá: -
[<__main__.Class instance at 0x6311b2c>, <__main__.Class instance at 0x63117ec>] 0 uno 1 duo 2 ['uno', 'duo']
fuente