Reputation: 686
I'm trying to create a class that populates a list of structured data items along with some methods for populating the list from files and IO devices.
I'm having a problem with my method that fills out a new data structure and appends it to a list. It's set-up as a coroutine that fills up a temporary structure with data from the (yield) function. When it's done it appends the data to the list (e.g. self.list.append(newdata)). My problem is that this append happens by reference and I can't figure out how to initialize newdata to new memoryspace. What winds up happening is I have a list of data all pointing to the same data structure (e.g. "myclass.list[n] is myclass.list[m]" always yields TRUE). Can anyone tell me how to make this work?
If I were writing in C++, I would just need to do "newdata = new * mydatastructure;" after each loop iteration... I just can't figure out how to do this in python.... am I way off course here?
Upvotes: 3
Views: 4912
Reputation: 11026
new
is syntactic sugar for mydatastructure* = malloc(sizeof(mydatastructure));
(or something like that, it's been a while). It allocates the appropriate amount of memory on the heap for your what-have-you, and if you use the constructor (in C++) it initializes the memory.
Python takes care of this for you. Technically, there is a similar routine in Python, called __new__
, which controls the allocation. But, you rarely need to override this on your objects.
The constructor for Python objects is called __init__
. When you call __init__
, __new__
is actually called first. So, when you construct objects in Python, you are automatically allocating new memory for them, and each one is different. As Benjamin pointed out, the constructor syntax (foo = Foo()
) is the way you call __init__
without actually typing __init__()
.
Your problem lies elsewhere in your code, unfortunately.
By the way, if you really want to be sure that two variables reference the same object, you can use the id()
function to get the reference number. The is
keyword compares these reference numbers, in contrast to the ==
operator which uses the __eq__
method of objects to compare them.
Upvotes: 3
Reputation: 1575
My problem is that this append happens by reference and I can't figure out how to initialize newdata to new memoryspace.
If you're trying to append objects into a list by value, you might want to use something like copy.copy or copy.deepcopy to make sure what is being appended is copied.
>>> # The Problem
>>> class ComplexObject:
... def __init__(self, herp, derp):
... self.herp = herp
... self.derp = derp
...
>>> obj = ComplexObject(1, 2)
>>> list = []
>>> list.append(obj)
>>> obj.derp = 5
>>> list[0].derp
5
>>> # obj and list[0] are the same thing in memory
>>> obj
<__main__.ComplexObject instance at 0x0000000002243D48>
>>> list[0]
<__main__.ComplexObject instance at 0x0000000002243D48>
>>> # The solution
>>> from copy import deepcopy
>>> list = []
>>> obj = ComplexObject(1,2)
>>> list.append(deepcopy(obj))
>>> obj.derp = 5
>>> list[0].derp
2
>>> obj
<__main__.ComplexObject instance at 0x0000000002243D48>
>>> list[0]
<__main__.ComplexObject instance at 0x000000000224ED88>
This is my attempt at actually solving your problem from your description without seeing any code. If you're more interested in allocation/constructors in Python, refer to another answer.
Upvotes: 2