views:

2795

answers:

5

Hi,

I'm trying to create a Python script that opens several databases and compares their contents. In the process of creating that script, I've run into a problem in creating a list whose contents are objects that I've created.

I've simplified the program to its bare bones for this posting. First I create a new class, create a new instance of it, assign it an attribute and then write it to a list. Then I assign a new value to the instance and again write it to a list... and again and again...

Problem is, it's always the same object so I'm really just changing the base object. When I read the list, I get a repeat of the same object over and over.

So how do you write objects to a list within a loop?

Thanks,

Bob J

Here's my simplified code

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

# So how do I (append, extend, copy or whatever) the elements of simpleList so that each entry
# contains a different instance of the object instead of all pointing to the same one?
+1  A: 

Create a new instance each time, where each new instance has the correct state, rather than continually modifying the state of the same instance.

Alternately, store an explicitly-made copy of the object (using the hint at this page) at each step, rather than the original.

joel.neely
+1: Never reuse an object; create a new one. They're cheap!
S.Lott
+7  A: 

You demonstrate a fundamental misunderstanding.

You never created an instance of SimpleClass at all, because you didn't call it.

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

Or, if you let the class take parameters, instead, you can use a list comprehension.

simplelist = [SimpleClass(count) for count in xrange(4)]
ironfroggy
A: 

If I understand correctly your question, you ask a way to execute a deep copy of an object. What about using copy.deepcopy?

import copy

x = SimpleClass()

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

A deepcopy is a recursive copy of the entire object. For more reference, you can have a look at the python documentation: http://www.python.org/doc/2.5.2/lib/module-copy.html

Roberto Liffredo
Reusing an object -- deep copy or clone -- is a common n00b confusion. Sometimes you can't answer the question the appear to ask; sometimes you have to answer the question they should have asked.
S.Lott
+2  A: 

It shouldn't be necessary to recreate the SimpleClass object each time, as some are suggesting, if you're simply using it to output data based on its attributes. However, you're not actually creating an instance of the class; you're simply creating a reference to the class object itself. Therefore, you're adding a reference to the same class attribute to the list (instead of instance attribute), over and over.

Instead of:

x = SimpleClass

you need:

x = SimpleClass()
Daniel
+1  A: 

To fill a list with seperate instances of a class, you can use a for loop in the declaration of the list. The * multiply will link each copy to the same instance.

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

and then access the instances through the index of the list.

instancelist[5].attr1 = 'whamma'
Sir Oddfellow