-
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
455: Common Python Interview Questions on Mutability
If you're prepping for a Python interview, mutability is one of those "gotcha" areas that interviewers love. It's not usually about whether you know what a list is, but whether you understand how Python handles objects in memory. I've seen senior devs stumble on these because they rely on intuition from other languages that doesn't quite apply here.
Why does my default list keep growing every time I call the function?
This is probably the most common Python interview question. You'll see a snippet where a function has a default argument like def add_item(item, my_list=[]):, and the interviewer will ask what happens when you call it three times without providing a list.
Here's the deal: Python evaluates default arguments once, at the moment the function is defined, not every time the function is called. That empty list [] is created once and stored in the function object. Every subsequent call that doesn't provide its own list is reusing that same exact object in memory.
def add_to_task_list(task, tasks=[]):
tasks.append(task)
return tasks
print(add_to_task_list("Clean room")) # ['Clean room']
print(add_to_task_list("Buy milk")) # ['Clean room', 'Buy milk']
# Wait, what? It remembered the first call!
To fix this, always use None as the default and initialize the mutable object inside the function. It's a pattern you should memorize; it's the "correct" way to handle this in professional code.
def add_to_task_list(task, tasks=None):
if tasks is None:
tasks = []
tasks.append(task)
return tasks
When should I use "is" instead of "==" for lists or dictionaries?
I often see people use these interchangeably, but in an interview, that's a red flag. == checks for equality (do these two objects have the same contents?), while is checks for identity (are these two variables pointing to the exact same spot in memory?).
With mutable objects, this distinction is critical. If you create two different lists with the same items, they are equal, but they are not the same object.
list_a = [1, 2, 3]
list_b = [1, 2, 3]
print(list_a == list_b) # True - the values are the same
print(list_a is list_b) # False - they are different objects in memory
list_c = list_a
print(list_a is list_c) # True - list_c is just an alias for list_a
Pro tip: Use is when comparing to None (e.g., if val is None:), but almost always use == for actual data comparison.
Why can't I use a list as a key in a dictionary?
If you try to use a list as a dictionary key, Python will throw a TypeError: unhashable type: 'list'. Interviewers ask this to see if you understand "hashability."
Dictionaries use a hash table for lightning-fast lookups. For this to work, the key must have a hash value that never changes during its lifetime. Since lists are mutable, you could change the contents of the list after using it as a key. If the content changes, the hash would change, and Python would "lose" the value associated with that key in the hash table.
If you need a collection of items as a key, use a tuple. Tuples are immutable, making them hashable and perfectly valid as dictionary keys.
# This crashes
# my_dict = {[1, 2]: "coordinates"}
# This works perfectly
my_dict = {(1, 2): "coordinates"}
print(my_dict[(1, 2)]) # "coordinates"
I copied my list, but changing the inner list still messed up the original. What happened?
This is the "Shallow Copy vs. Deep Copy" trap. When you use list.copy() or a slice like [:], you're creating a shallow copy. This means Python creates a new outer list, but the elements inside that list are still references to the original objects.
If your list contains other mutable objects (like a list of lists), a shallow copy isn't enough.
original = [[1, 2], [3, 4]]
shallow = original.copy()
shallow[0][0] = 99
print(original) # [[99, 2], [3, 4]] - The original was modified!
To truly decouple the two, you need the copy module's deepcopy() function, which recursively copies every object found within the original. It's slower and uses more memory, but it's the only way to ensure total independence.
📋 Practical Task
Fixing the Persistent User Session List
You are reviewing a teammate's code for a user session manager. They've written a function that tracks the pages a user visits during their session. However, they've encountered a bug: every new user seems to "inherit" the page history of the previous users.
Your Task: Modify the track_visit function below to ensure that each user starts with a fresh, empty list if no history is provided, preventing data from leaking between sessions.
def track_visit(page_name, history=[]):
history.append(page_name)
return history
# Test Case 1: User A visits Home and About
user_a = track_visit("Home")
user_a = track_visit("About", user_a)
print(f"User A: {user_a}") # Expected: ['Home', 'About']
# Test Case 2: User B visits Contact
# Currently, this returns ['Home', 'About', 'Contact'] due to the bug!
user_b = track_visit("Contact")
print(f"User B: {user_b}") # Expected: ['Contact']
There are no comments for now.