Skip to content

Instantly share code, notes, and snippets.

@andersy005
Last active March 7, 2018 05:04
Show Gist options
  • Save andersy005/303ff7fa126032e67cfcb0072663ecf9 to your computer and use it in GitHub Desktop.
Save andersy005/303ff7fa126032e67cfcb0072663ecf9 to your computer and use it in GitHub Desktop.
Shallow and Deep Copy in Python

Shallow Copy

>>> x = 3
>>> y = x
>>> print(id(x), id(y))
9251744 9251744
>>> y = 4
>>> print(id(x), id(y))
9251744 9251776
>>> print(x,y)
3 4
>>> 

Python creates only real copies, if it has to, i.e. if the user, the programmer, explicitly demands it.

Copying a list

>>> colors1 = ["red", "blue"] 
>>> colors2 = colors1
>>> colors1
['red', 'blue']
>>> colors2
['red', 'blue']
>>> print(id(colors1), id(colors2))
139767907255944 139767907255944
>>> colors2 = ["rouge", "vert"]
>>> colors2
['rouge', 'vert']
>>> colors1
['red', 'blue']
>>> print(id(colors1), id(colors2))
139767907255944 139767907256072
>>> 
>>> colors = ["red", "blue"]
>>> colors2 = colors
>>> print(id(colors), id(colors2))
139767907297288 139767907297288
>>> colors2[1] = "green"
>>> colors2
['red', 'green']
>>> colors
['red', 'green']
>>> print(id(colors), id(colors2))
139767907297288 139767907297288
>>> 

The explanation is that we didn't assign a new object to colors2. We changed colors2 inside or as it is usually called "in-place". Both variables "colors" and "colors2" still point to the same list object.

Copy with the slice Operator

It's possible to completely copy shallow list structures with the slice operator without having any of the side effects

>>> list1 = ['a', 'b', 'c', 'd']
>>> list2 = list1[:]
>>> list1
['a', 'b', 'c', 'd']
>>> list2
['a', 'b', 'c', 'd']
>>> list2[1] = 'popeyes'
>>> list1
['a', 'b', 'c', 'd']
>>> list2
['a', 'popeyes', 'c', 'd']

But as soon as a list contains sublists, we have another difficulty: The sublists are not copied but only the references to the sublists.

>>> lst1 = ['a', 'b', ['ab', 'ba']]
>>> lst2 = lst1[:]
>>> lst1
['a', 'b', ['ab', 'ba']]
>>> lst2
['a', 'b', ['ab', 'ba']]
>>> lst2[0] = 'Hello'
>>> lst1
['a', 'b', ['ab', 'ba']]
>>> lst2
['Hello', 'b', ['ab', 'ba']]
>>> lst2[2][1] = 'World'


>>> lst1
['a', 'b', ['ab', 'World']]
>>> lst2
['Hello', 'b', ['ab', 'World']]
>>> 

Deep Copy

A solution to the described problems provide the module "copy". This module provides the method "deepcopy", which allows a complete or deep copy of an arbitrary list, i.e. shallow and other lists.

>>> from copy import deepcopy
>>> 
>>> lst1 = ['a','b',['ab','ba']]
>>> 
>>> lst2 = deepcopy(lst1)
>>> 
>>> lst1
['a', 'b', ['ab', 'ba']]
>>> lst2
['a', 'b', ['ab', 'ba']]
>>> id(lst1)
139716507600200
>>> id(lst2)
139716507600904
>>> id(lst1[0])
139716538182096
>>> id(lst2[0])
139716538182096
>>> id(lst2[2])
139716507602632
>>> id(lst1[2])
139716507615880
>>> 

We can see by using the id function that the sublist has been copied, because id(lst2[2]) is different from id(lst1[2]). An interesting fact is that the strings are not copied: lst1[0] and lst2[0] reference the same string.

>>> lst2[2][1] = "d"
>>> lst2[0] = "c"
>>> print(lst1)
['a', 'b', ['ab', 'ba']]
>>> print(lst2)
['c', 'b', ['ab', 'd']]
>>> 

This is true for lst1[1] and lst2[1] as well, of course.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment