Python
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Data Types
-
Section 3: Collections
-
39: Set Operations: Union, Intersection, Difference
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Turtle Graphics and Early Practice Projects
-
Section 7: Working with Files and I/O
-
Section 8: Regular Expressions
-
Section 9: Object-Oriented Python
-
Section 10: Error Handling
-
Section 11: Modules and Packages
-
Section 12: Iterators, Generators, and Functional Tools
-
Section 13: Decorators and Metaprogramming
-
Section 14: Concurrency and Parallelism
-
Section 15: Working with Dates, Times, and Numbers
-
Section 16: Standard Library Deep Dive I: Data Structures
-
Section 17: Standard Library Deep Dive II: System and Introspection
-
Section 18: Standard Library Deep Dive III: Security and Encoding
-
Section 19: Standard Library Deep Dive IV: Text and Data Utilities
-
Section 20: Networking and Web Basics
-
Section 21: Working with Databases
-
Section 22: Testing and Quality
-
Section 23: Advanced Typing
-
Section 24: Context Managers and Resource Handling
-
Section 25: Text, Unicode, and Binary Data
-
Section 26: More Functional and Iteration Tools
-
Section 27: Data Validation and Configuration
-
Section 28: Working with Images and Media
-
Section 29: Property-Based and Documentation Testing
-
Section 30: Packaging and Deployment
-
Section 31: Performance and Internals
-
Section 32: Design Patterns in Python
-
Section 33: GUI Programming
-
Section 34: Security Basics
-
Section 35: Data Structures and Algorithms
-
Section 36: Practical Projects
-
Section 37: Capstone Projects
-
Section 38: Interview and Algorithm Practice
-
Section 39: Writing Idiomatic Python
45: Copying Collections: Shallow vs Deep Copy
I can almost guarantee that at some point, you've written a line of code like new_list = old_list and assumed you just created a backup of your data. It feels intuitive. In your head, you're thinking, "I'm taking the values from here and putting them over there." But in Python, that is fundamentally not what is happening.
The Assignment Operator is not a Copy
When you use the equals sign with a collection (like a list or a dictionary), you aren't copying the data. You're just creating a new name that points to the exact same spot in your computer's memory. I call this "aliasing."
# The "Oh no" moment
original_profile = ["Alice", "Developer", ["Python", "Rust"]]
backup_profile = original_profile
# Let's change the backup
backup_profile[0] = "Bob"
print(original_profile)
# Output: ["Bob", "Developer", ["Python", "Rust"]]
Notice how Alice vanished? Because original_profile and backup_profile are just two different labels for the same object. If you change one, you change the other. This is a classic source of bugs that can haunt a codebase for weeks if you aren't looking for it.
Shallow Copies only go skin deep
To actually create a separate object, you can use the .copy() method or the list() constructor. This is what we call a shallow copy. It creates a new collection object, but it doesn't recursively copy the objects inside that collection.
For a simple list of strings or numbers, this works perfectly. But as soon as you have "nested" collections (like a list inside a list), you're back in danger.
# Trying to be safer with a shallow copy
original_profile = ["Alice", "Developer", ["Python", "Rust"]]
backup_profile = original_profile.copy()
# Changing a top-level element is now safe
backup_profile[0] = "Bob"
print(original_profile[0]) # Still "Alice" - Success!
# But wait... let's change the nested list
backup_profile[2].append("Go")
print(original_profile[2]) # Output: ["Python", "Rust", "Go"]
What happened? The shallow copy created a new outer list, but the inner list (the skills list) was still just a reference to the original. The "skin" was copied, but the "guts" were shared. Honestly, this is where most Python developers get tripped up. It's a subtle distinction, but a critical one.
Deep Copying for fully independent data
If you need a total disconnect—where no matter how deep the nesting goes, the new object is entirely independent—you need the copy module and its deepcopy() function. This tells Python to walk through the entire structure and recursively copy every single object it finds.
import copy
original_profile = ["Alice", "Developer", ["Python", "Rust"]]
backup_profile = copy.deepcopy(original_profile)
# Now we can be as destructive as we want
backup_profile[2].append("Go")
backup_profile[0] = "Bob"
print(original_profile)
# Output: ["Alice", "Developer", ["Python", "Rust"]]
# Everything is preserved.
A word of caution: deepcopy is significantly slower and uses more memory than a shallow copy because it has to do so much more work under the hood. Don't use it by default; use it when you actually have nested mutable data that needs to be isolated.
📋 Practical Task
Fixing the Game State Undo Bug
You are building a simple RPG. You've implemented an "Undo" feature that saves the current game state before the player makes a move. However, you've discovered a bug: when the player gains an item in the current game, that item also magically appears in the "undo" backup, making the undo feature useless.
Your Task: Modify the save_game_state function below to ensure the backup is a completely independent copy of the state, so that modifications to the current_state do not affect the undo_stack.
import copy
# The current state of the game
# Format: { "player_name": str, "inventory": list }
current_state = {
"player_name": "Valerius",
"inventory": ["Rusty Sword", "Health Potion"]
}
undo_stack = []
def save_game_state(state):
# BUG: This currently performs a shallow copy (or assignment)
# Fix this line to ensure the inventory list is also copied
backup = state.copy()
undo_stack.append(backup)
# --- Test Sequence ---
save_game_state(current_state)
# Player finds a legendary item
current_state["inventory"].append("Dragon Scale Shield")
# Check if the backup was corrupted
if "Dragon Scale Shield" in undo_stack[0]["inventory"]:
print("Bug still exists: The backup was modified!")
else:
print("Success: The backup is independent!")
There are no comments for now.