Search code examples
pythonlistcopyshallow-copy

Making a shallow copy of a list of objects


I want to pass a list of objects to a function, get a new modified list but keep the original list unchanged. Like this:

class classA():
def __init__(self):
    field1 = 0
    field2 = 0

def func(array):    
    array2 = copy.copy(array) #array[:] gives the same result
    for index, q in enumerate(array):
        if index == 1:
            array2[index].field1 = 5
    return array2

array = [classA(),classA(),classA(),classA()]
array_new = func(array)

print array[1].field1
print array_new[1].field1

It prints 5 and 5. Both are changed. I understand that the list itself is shallow copied, but for objects the value of reference is copied (which is why they are tied).

To shallow copy objects as well, I tried this:

array2 = [copy.copy(o) for o in array]

but it gives me an error:

  print array[1].field1
AttributeError: classA instance has no attribute 'field1'

What is an easy way to shallow copy the objects inside the list too? Or maybe in general an easier way to do what I am trying to do?


Solution

  • You need to make field1 and field2 instance attributes of classA:

    def __init__(self):
        self.field1 = 0
        self.field2 = 0
    

    Without prefixing the names with self., field1 and field2 will be created as local names that are only available inside the __init__ method.


    Also, it looks like you should actually be doing a deep copy of the list:

    array2 = copy.deepcopy(array)
    

    This will copy both the list object itself as well as all of its items. Doing a shallow copy will only copy the list object. From the docs:

    A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.

    A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.