copy — Shallow and deep copy operations

Assignment statements in Python do not actually copy objects; they create bindings between a target and an object (meaning two variables point to the exact same list in memory). For collections that are mutable or contain mutable items, a true copy is sometimes needed so one can change one copy without altering the other.

The copy module provides these operations.

import copy

The Problem

If you assign a list to a new variable, they share memory.

original = [1, 2, [3, 4]]
fake_copy = original

fake_copy[0] = 99
print(original) # [99, 2, [3, 4]] -> The original changed!

Shallow Copy (copy.copy)

A shallow copy constructs a new compound object and then inserts references into it to the objects found in the original.

import copy

original = [1, 2, [3, 4]]
shallow = copy.copy(original) # Same as original.copy() or list(original)

# Changing top-level elements is safe
shallow[0] = 99
print(original) # [1, 2, [3, 4]] - Original is untouched!

# HOWEVER, changing nested elements affects both!
shallow[2][0] = 'Hacked'
print(shallow)   # [99, 2, ['Hacked', 4]]
print(original)  # [1, 2, ['Hacked', 4]]

Deep Copy (copy.deepcopy)

A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original. This breaks all links between the objects.

import copy

original = [1, 2, [3, 4]]
deep = copy.deepcopy(original)

deep[2][0] = 'Hacked'

print(deep)     # [1, 2, ['Hacked', 4]]
print(original) # [1, 2, [3, 4]] - Completely safe!

API Reference

Core Functions

Function Description
copy.copy(x) Return a shallow copy of x.
copy.deepcopy(x, memo=None) Return a deep copy of x. The memo dict is used to avoid infinite recursion on self-referential structures.

Magic Methods

Classes can use magic methods to control how they are copied.

Magic Method Description
__copy__(self) Called on a class to define its shallow copy behavior.
__deepcopy__(self, memo) Called on a class to define its deep copy behavior.