Shallow copy creates a new top-level object, but nested objects (list elements, nested dictionaries, etc.) share memory with the original. Deep copy recursively copies all levels of objects.
It can be used through the copy module:
import copy original = [[1, 2], [3, 4]] shallow = copy.copy(original) deep = copy.deepcopy(original) shallow[0][0] = 99 # Changes both original and shallow print(original) # [[99, 2], [3, 4]] # Now with deep original = [[1, 2], [3, 4]] deep = copy.deepcopy(original) deep[0][0] = 99 print(original) # [[1, 2], [3, 4]]
copy.copy(obj): copies only the "wrapper"copy.deepcopy(obj): fully recursive copyingWhat happens when copying a tuple that contains mutable objects?
tuple is immutable, but its elements can be mutable (e.g., a list). Shallow copy and deep copy differ:
import copy t = ([1, 2], [3, 4]) shallow = copy.copy(t) deep = copy.deepcopy(t) shallow[0][0] = 99 print(t) # ([99, 2], [3, 4]) # With deep copy: t = ([1, 2], [3, 4]) deep = copy.deepcopy(t) deep[0][0] = 88 print(t) # ([1, 2], [3, 4])
Story
In a document processing application, data was stored in a list inside a dictionary. When copying objects using copy.copy, nested elements were unintentionally changed when modifying the new object. As a result, the original data was changed in other parts of the system! Data corruption occurred. It was fixed only by replacing it with deepcopy.
Story
In a machine learning project, when saving model hyperparameters, a list of configurations was copied using standard assignment and shallow copy, causing different experiments to mutually change their parameters. The source of the bug was found after diagnosing the behavior of copying nested lists via deepcopy.
Story
In financial software, deep copy was accidentally applied to an object that included an open file (handle), which resulted in TypeError: cannot pickle '_io.TextIOWrapper' object — because copy.deepcopy under the hood uses pickle. It was fixed through explicit handling of such fields or calling shallow copy.