AzureMinotaur
AzureMinotaur

Reputation: 696

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?

Upvotes: 0

Views: 206

Answers (2)

user2555451
user2555451

Reputation:

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.

Upvotes: 2

bosnjak
bosnjak

Reputation: 8614

The way you defined it, field1 is not a field/attribute of the class, it is a local variable in the __init__() method. Instead, the proper way to declare a class field would be like this:

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

Upvotes: 0

Related Questions