Python Common Mistakes
In this page:
Mutable Default Arguments Trap
Using a mutable object like a list or dict as a function's default parameter value is a classic Python trap: default values are evaluated only once, at function-definition time, so every call that doesn't pass its own argument ends up sharing and mutating that exact same object.
Example: Mutable Default Arguments Trap
def add_item(item, cart=[]):
cart.append(item)
return cart
print(add_item("apple"))
print(add_item("banana")) # unexpectedly shares the same list
Modifying Lists During Iteration
Removing or inserting items from a list while iterating over it directly shifts the underlying indices mid-loop, causing Python to silently skip elements or raise an unexpected IndexError. The safe fix is to iterate over a copy of the list (for x in list[:]) or build a new filtered list instead of mutating the original in place.
Example: Modifying Lists During Iteration
numbers = [1, 2, 3, 4]
for n in numbers[:]: # iterate over a copy
if n % 2 == 0:
numbers.remove(n)
print(numbers)
Shadowing Built-in Functions
Naming a variable list, dict, str, or another built-in overwrites that name within the current scope, so any later code in that scope that tries to use the real built-in (like calling list() to make a new list) breaks with a confusing TypeError instead of a clear naming-conflict warning.
Example: Shadowing Built-in Functions
list = [1, 2, 3] # shadows the built-in list()
print(list)
del list # restore the built-in
print(list([4, 5]))
Checking with is vs ==
== compares whether two objects have equal *values*, while is compares whether two names refer to the exact same object in memory. Two separately-created lists with identical contents are equal (== is True) but are not the same object (is is False) -- conflating the two leads to subtle bugs, especially with None checks, which should always use is None.
Example: Checking with is vs ==
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b)
print(a is b)
Referencing Before Assignment
Reading a local variable before any value has been assigned to it inside the same function raises UnboundLocalError, even if a variable with the same name exists at module scope -- because assigning anywhere inside a function makes Python treat that name as local for the *entire* function body, not just from the assignment line onward.
Example: Referencing Before Assignment
def show():
try:
print(count)
count = 1
except UnboundLocalError as e:
print("Error:", e)
count = 10
show()
Chapter Quiz — Complete all 15 topics to unlock
0/15 topics done
Complete these topics first:
- Python PEP 8 Style Guide
- Python Debugging Techniques
- Python Testing with unittest
- Python Common Mistakes
- Python Interview Questions
- Python map() & filter()
- Python reduce()
- Python zip() & enumerate()
- Python sorted() & key Functions
- Python Comprehensions Advanced
- Python Turtle Graphics
- Python tkinter Introduction
- Python tkinter Widgets
- Python pygame Introduction
- Python Mini Projects