The Secret Life of Python: The Matryoshka Trap

Published: (January 8, 2026 at 08:30 PM EST)
3 min read
Source: Dev.to

Source: Dev.to

Timothy’s Nested Plan

Timothy was humming a tune as he organized the library’s archives. He felt invincible, having mastered the “slice” ([:]) syntax that allowed him to clone lists and avoid the curse of aliasing.

“Margaret, I’m reorganizing the library sections. I made a master map of the shelves and a backup before I move anything around. Look at this beautiful shallow copy.”

He displayed his code, confident in his new skills.

# Timothy's Nested Plan
shelf_A = ["Fiction", "Mystery"]
shelf_B = ["Biography", "History"]

# The Master Layout: a list of lists
library_layout = [shelf_A, shelf_B]

# The Backup: using the slice trick
backup_layout = library_layout[:]  # (Surely this clones everything... right?)

# Move "Mystery" to a new location in the backup
backup_layout[0].remove("Mystery")

print(f"Backup Shelf A: {backup_layout[0]}")
print(f"Master Shelf A: {library_layout[0]}")

Console output

Backup Shelf A: ['Fiction']
Master Shelf A: ['Fiction']

Timothy was stunned. The “Mystery” book had disappeared from the master layout as well, even though he thought the slice created a completely independent list.


The Shallow Copy Trap

Margaret explained that a slice (or list.copy()) creates a new outer container but shares references to any mutable objects inside it.

Original List        Backup List
   [Box 1]             [Box 2]
      |                   |
      +-------+   +-------+
              |   |
              v   v
           [Inner List]
          (Shared Data!)

When Timothy modified backup_layout[0], he was actually modifying the same inner list that library_layout[0] points to. This is the classic Matryoshka (nested‑doll) trap: a shallow copy only copies the first layer.


Deep Copy Solution

To obtain a completely independent copy—including all nested mutable objects—Timothy needed a deep copy.

import copy

shelf_A = ["Fiction", "Mystery"]
shelf_B = ["Biography", "History"]
library_layout = [shelf_A, shelf_B]

# Deep copy: recursively copies everything
backup_layout = copy.deepcopy(library_layout)

backup_layout[0].remove("Mystery")

print(f"Backup Shelf A: {backup_layout[0]}")
print(f"Master Shelf A: {library_layout[0]}")

Output

Backup Shelf A: ['Fiction']
Master Shelf A: ['Fiction', 'Mystery']

copy.deepcopy() walks the entire object graph, cloning each mutable element it encounters, so changes to the backup never affect the original.


Performance Considerations

  • Why isn’t deep copy the default?
    Deep copying is expensive in both time and memory. For small or flat structures the overhead is negligible, but cloning large, deeply nested structures repeatedly can become a performance bottleneck.

  • Python’s default philosophy
    Python favors speed; shallow copies are cheap and sufficient for many use‑cases. When safety for nested data is required, you must request it explicitly.


Guidelines for Copying

SituationRecommended Copy
Flat list (e.g., [1, 2, 3])Shallow copy (list[:], list.copy(), or copy.copy(x))
Nested list/dict (e.g., [[1, 2], [3, 4]])Deep copy (copy.deepcopy(x))
Need a generic shallow copy for any objectcopy.copy(x) (works on lists, dicts, custom objects)
Need a completely independent clone of a complex structurecopy.deepcopy(x)

Quick reference

import copy

# Shallow copy (first layer only)
shallow = original_list[:]          # or original_list.copy()
shallow_generic = copy.copy(original)  # works on any object

# Deep copy (full recursion)
deep = copy.deepcopy(original)

When to Use Deep Copy

  • Nested mutable containers – lists of lists, dicts containing lists, objects containing other mutable objects.
  • Isolation required – when modifications to the copy must never affect the original, even deep inside the structure.
  • Testing or sandboxing – creating a safe sandboxed version of data for experiments.

For simple, flat data structures, a shallow copy remains the most efficient choice.


The story continues in the next episode, “The Loophole,” where modifying a list while iterating over it creates a chaotic, skipping timeline.

Back to Blog

Related posts

Read more »

Problem 10: Duplicate Removal

Problem Description We need a function that removes duplicates from a list while preserving the original order of elements. Example remove_duplicates1, 2, 2, 3...

The Secret Life of Python: The Loophole

The trap of modifying a list while iterating over it and how to fix it. Timothy was staring at a list of sensor data on his screen. > “I told it to remove the e...