Timothy the Librarian thought he understood his bookcase system perfectly. Then came the day that changed everything—the day he discovered that some bookcases aren't what they seem.
The Mysterious Shared Bookcase
Picture Timothy managing the library's special collections. He creates what he thinks are two separate bookcases for different reading groups:
# Timothy sets up reading materials
classics = ["Pride and Prejudice", "Jane Eyre"]
book_club_a = classics
book_club_b = classics
"Perfect!" Timothy thinks. "Two reading groups, each with their own bookcase." But when Book Club A decides they want to add "Wuthering Heights" to their collection, something strange happens:
book_club_a.append("Wuthering Heights")
print(book_club_b) # ["Pride and Prejudice", "Jane Eyre", "Wuthering Heights"]
Book Club B suddenly has the new book too! Timothy stares in bewilderment. How did one group's addition appear in the other's collection?
The Truth About Bookcase Labels
Here's Timothy's revelation: he wasn't creating separate bookcases at all. He was creating multiple labels pointing to the same physical bookcase. In Python's world, when you write book_club_a = classics
, you're not copying the bookcase—you're creating a new name tag that points to the existing one.
Think of it like this: Timothy has one bookcase in the corner, but he's hung three different signs on it: "classics," "book_club_a," and "book_club_b." When anyone adds or removes books using any of these signs, they're all working with the same physical bookcase.
The Identity Crisis
Timothy develops a simple test to check if two labels point to the same bookcase. He calls it the "identity check":
# Timothy's identity test
print(book_club_a is classics) # True - same bookcase!
print(id(book_club_a)) # Shows the bookcase's unique number
print(id(classics)) # Same number - confirmed!
The is
operator tells Timothy whether two names refer to the exact same bookcase, while id()
shows each bookcase's unique identification number—like a serial number stamped on the frame.
The Proper Duplication Technique
When Timothy actually needs separate bookcases, he learns to create true copies:
# Method 1: The slice copy
book_club_c = classics[:] # Creates a brand new bookcase
# Method 2: The copy method
book_club_d = classics.copy() # Also creates a new bookcase
# Method 3: The list constructor
book_club_e = list(classics) # Another way to create a new bookcase
Now when Book Club C adds "Emma," the other collections remain untouched. Timothy has learned to duplicate the bookcase itself, not just add more name tags.
The Function Parameter Trap
Timothy's biggest surprise comes when he creates a function to organize books:
def add_bestseller(bookcase):
bookcase.append("The Great Gatsby")
return bookcase
my_books = ["1984", "Brave New World"]
updated_books = add_bestseller(my_books)
print(my_books) # ["1984", "Brave New World", "The Great Gatsby"]
print(updated_books) # ["1984", "Brave New World", "The Great Gatsby"]
Timothy expected my_books
to stay unchanged, but the function modified his original bookcase! This happens because Python passes the bookcase itself (not a copy) to the function. When the function adds a book, it's adding to the original bookcase.
The Safe Function Pattern
Timothy develops a safer approach for functions that need to modify bookcases:
def add_bestseller_safely(bookcase):
new_bookcase = bookcase.copy() # Make a duplicate first
new_bookcase.append("The Great Gatsby")
return new_bookcase
my_books = ["1984", "Brave New World"]
updated_books = add_bestseller_safely(my_books)
print(my_books) # ["1984", "Brave New World"] - unchanged!
print(updated_books) # ["1984", "Brave New World", "The Great Gatsby"]
Now Timothy's original collection stays safe while he returns a modified copy.
The Nested Bookcase Complication
Just when Timothy thinks he understands everything, he encounters nested bookcases—bookcases containing other bookcases:
# A bookcase containing smaller bookcases
departments = [
["Fiction", "Non-Fiction"], # Literature department
["History", "Biography"] # Reference department
]
backup = departments.copy()
departments[0].append("Poetry")
print(backup) # [["Fiction", "Non-Fiction", "Poetry"], ["History", "Biography"]]
The copy()
method only duplicated the main bookcase, not the smaller bookcases inside it! Timothy discovers this is called a "shallow copy"—it copies the container but not the contents.
For truly independent nested bookcases, Timothy learns he needs to visit the Deep Copy Department:
import copy
# Timothy uses the special deep copying equipment
departments = [
["Fiction", "Non-Fiction"],
["History", "Biography"]
]
true_backup = copy.deepcopy(departments)
departments[0].append("Poetry")
print(true_backup) # [["Fiction", "Non-Fiction"], ["History", "Biography"]]
Now the backup remains completely unchanged! The deepcopy()
function creates new bookcases all the way down, even copying the smaller bookcases inside the main one.
Timothy's Mutation Guidelines
After his moving day disaster, Timothy establishes clear rules for the library:
When you want separate bookcases:
- Use
new_list = old_list.copy()
for simple collections - Use
new_list = old_list[:]
for the same result - Be aware that nested collections need special handling
When checking if bookcases are the same:
- Use
list1 is list2
to check identity (same bookcase) - Use
list1 == list2
to check contents (same books)
When writing functions:
- Decide whether to modify the original bookcase or return a new one
- Make your choice clear in the function name and documentation
- When in doubt, copy first to avoid surprises
The key insight Timothy learned: in Python, assignment creates new labels for existing bookcases, not new bookcases. Understanding this difference prevents countless headaches and mysterious bugs.
Remember: every time you see strange behavior where changing one variable affects another, ask yourself—are these really separate bookcases, or just different labels on the same one?
Aaron Rose is a software engineer and technology writer at tech-reader.blog and the author of Think Like a Genius.
Top comments (0)