Demystifying Copying in Python: Shallow vs. Deep

Demystifying Copying in Python: Shallow vs. Deep

In the realm of Python, assigning one variable to another may not always be as straightforward as it seems. When dealing with mutable objects like lists and dictionaries, a mere assignment creates a reference, not a true copy. The impact? Modifications to one affect the other. Enter the copy module, offering salvation in the form of shallow and deep copies.

list_a = [1, 2, 3, 4, 5]
list_b = list_a

list_a[0] = -10
print(list_a)  # [-10, 2, 3, 4, 5]
print(list_b)  # [-10, 2, 3, 4, 5]

A change in one echoes in the other, a symphony of shared references.

Shallow Copy: Tread Lightly on Nested Grounds

import copy
list_a = [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
list_b = copy.copy(list_a)

list_b[0][0] = -10
print(list_a)  # [[-10, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
print(list_b)  # [[-10, 2, 3, 4, 5], [6, 7, 8, 9, 10]]

Shallow copies exhibit caution: they grant independence at the first level but remain entangled deeper.

Deep Copy: Breaking Chains

import copy
list_a = [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
list_b = copy.deepcopy(list_a)

list_b[0][0] = -10
print(list_a)  # [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
print(list_b) # [[-10, 2, 3, 4, 5], [6, 7, 8, 9, 10]]

Deep copies liberate, ensuring modifications in one realm don't cast shadows on another.

Navigating Custom Objects

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

# Reference link
p1 = Person('Alex', 27)
p2 = p1
p2.age = 28
print(p1.age)  # 28
print(p2.age)  # 28

# Shallow copy
import copy
p1 = Person('Alex', 27)
p2 = copy.copy(p1)
p2.age = 28
print(p1.age)  # 27
print(p2.age)  # 28

Understanding copying is vital, especially when nested structures or custom objects come into play. Shallow copies tiptoe, while deep copies break free. Choose wisely and code confidently in the dynamic realm of Python!