Shallow vs Deep Copying - Advanced Python 20
Tutorial about shallow vs deep copying in Python and the `copy` module.
In Python, assignment statements (obj_b = obj_a
) do not create real copies. It only creates a new variable with the same reference. So when you want to make actual copies of mutable objects (lists, dicts) and want to modify the copy without affecting the original, you have to be careful.
For 'real' copies we can use the copy
module. However, for compound/nested objects (e.g. nested lists or dicts) and custom objects there is an important difference between shallow and deep copying: - shallow copies: Only one level deep. It creates a new collection object and populates it with references to the nested objects. This means modyfing a nested object in the copy deeper than one level affects the original. - deep copies: A full independent clone. It creates a new collection object and then recursively populates it with copies of the nested objects found in the original.
Assignment operation¶
This will only create a new variable with the same reference. Modifying one will affect the other.
list_a = [1, 2, 3, 4, 5]
list_b = list_a
list_a[0] = -10
print(list_a)
print(list_b)
[-10, 2, 3, 4, 5]
[-10, 2, 3, 4, 5]
Shallow copy¶
One level deep. Modifying on level 1 does not affect the other list. Use copy.copy()
, or object-specific copy functions/copy constructors.
import copy
list_a = [1, 2, 3, 4, 5]
list_b = copy.copy(list_a)
# not affects the other list
list_b[0] = -10
print(list_a)
print(list_b)
[1, 2, 3, 4, 5]
[-10, 2, 3, 4, 5]
But with nested objects, modifying on level 2 or deeper does affect the other!
import copy
list_a = [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
list_b = copy.copy(list_a)
# affects the other!
list_a[0][0]= -10
print(list_a)
print(list_b)
[[-10, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
[[-10, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
Note: You can also use the following to create shallow copies:
# shallow copies
list_b = list(list_a)
list_b = list_a[:]
list_b = list_a.copy()
Deep copies¶
Full independent clones. Use copy.deepcopy()
.
import copy
list_a = [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
list_b = copy.deepcopy(list_a)
# not affects the other
list_a[0][0]= -10
print(list_a)
print(list_b)
[[-10, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
Custom objects¶
You can use the copy
module to get shallow or deep copies of custom objects.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
# Only copies the reference
p1 = Person('Alex', 27)
p2 = p1
p2.age = 28
print(p1.age)
print(p2.age)
28
28
# shallow copy
import copy
p1 = Person('Alex', 27)
p2 = copy.copy(p1)
p2.age = 28
print(p1.age)
print(p2.age)
27
28
Now let's make a nested object:
class Company:
def __init__(self, boss, employee):
self. boss = boss
self.employee = employee
# shallow copy will affect nested objects
boss = Person('Jane', 55)
employee = Person('Joe', 28)
company = Company(boss, employee)
company_clone = copy.copy(company)
company_clone.boss.age = 56
print(company.boss.age)
print(company_clone.boss.age)
print()
# deep copy will not affect nested objects
boss = Person('Jane', 55)
employee = Person('Joe', 28)
company = Company(boss, employee)
company_clone = copy.deepcopy(company)
company_clone.boss.age = 56
print(company.boss.age)
print(company_clone.boss.age)
56
56
55
56
FREE VS Code / PyCharm Extensions I Use
✅ Write cleaner code with Sourcery, instant refactoring suggestions: Link*
Python Problem-Solving Bootcamp
🚀 Solve 42 programming puzzles over the course of 21 days: Link*