Python: How to copy a list of a dictionaries

Viewed 116

Python 3. I'm trying to copy a list of a dictionaries without altering the original list. This doesn't seem to work the same way that copying a list does:

List of Dictionaries

list_of_dict = [{"A":"a", "B": "b"}]    
table_copy = list(list_of_dict)
for x in table_copy:
    x['B'] = 1

print(list_of_dict)
print(table_copy)

Yields

[{'A': 'a', 'B': 1}]
[{'A': 'a', 'B': 1}]

For reference this is how copying a list looks like this:

orig_list = [1,2,3]
copy_list = list(orig_list)
copy_list[1] = "a"
print(orig_list)
print(copy_list)

Yields what we expect

[1, 2, 3]
[1, 'a', 3]

How do you actually copy a list of dictionaries?

5 Answers

With the line of code, table_copy = list(list_of_dict) you are creating a new pointer (variable) but the underlying elements are not copied (which is shallow copy)

list_of_dict = [{"A":"a", "B": "b"}]    
table_copy = list(list_of_dict)

id(list_of_dict)
Out[8]: 2208287332232

id(table_copy)
Out[9]: 2208275740680

id(list_of_dict[0])
Out[10]: 2208275651624

id(table_copy[0])
Out[11]: 2208275651624 <== equal to id(list_of_dict[0])

You should use the copy module from the standard library which comes with two useful functions

copy(x):

Return a shallow copy of x.

deepcopy(x):

Return a deep copy of x.

For your problem,

from copy import deepcopy

list_of_dict = [{"A":"a", "B": "b"}]    
table_copy   = deepcopy(list_of_dict)

The thumb rule is to use, deepcopy when you have a complex object i.e. object containing other objects.

From the docs,

The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or class instances):

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.

list_of_dict = [{"A":"a", "B": "b"}]    
table_copy = list(d.copy() for d in list_of_dict)

You can use the deepcopy() of copy module.

Deep Copy

A deep copy creates a new object and recursively adds the copies of nested objects present in the original elements.

In [15]: import copy

In [16]: list_of_dict
Out[16]: [{'A': 23, 'B': 'b'}]

In [18]: table_copy=copy.deepcopy(list_of_dict)

In [19]: table_copy
Out[19]: [{'A': 23, 'B': 'b'}]

In [20]: table_copy[0]['A']=2

In [21]: table_copy
Out[21]: [{'A': 2, 'B': 'b'}]

In [22]: list_of_dict
Out[22]: [{'A': 23, 'B': 'b'}]

For More

A very easy way is to do a copy.deepcopy(). It onstructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.

import copy

list_of_dict = [{"A":"a", "B": "b"}]    
table_copy = copy.deepcopy(list_of_dict)

print(list_of_dict)
print(table_copy)

for x in table_copy:
    x['B'] = 1

print()
print(list_of_dict)
print(table_copy)

Output:

[{'A': 'a', 'B': 'b'}]
[{'A': 'a', 'B': 'b'}]

[{'A': 'a', 'B': 'b'}]
[{'A': 'a', 'B': 1}]

You can't create a new list just by basing it off of another, so you have to do something like this:

list = ['foo','fib']
duplicate = list[:]

Now, if you try to append something to 'list', it won't show up in 'duplicate'. However, if you were to do list = ['a','b']; duplicate = list, then it would also show up in 'duplicate'. If you try it with dictionaries, it also works.

list = [{1:1},{0:0}]
dupe = list[:]
list.append('e')
print list
print dupe

would give you this output:

[{1:1},{0:0},'e']
[{1:1},{0:0}]

EDIT: I have tried this in both 2 and 3 and it still works in either version.

Related