10 Common Python Pitfalls Every Developer Should Avoid
This article explains ten subtle Python pitfalls—including UnboundLocalError, mutable default arguments, the difference between x += y and x = x + y, tuple syntax, list‑of‑lists initialization, modifying a list while iterating, closure‑late binding with lambdas, __del__ interactions with garbage collection, inconsistent module imports, Python‑2‑to‑3 migration quirks, and the Global Interpreter Lock—providing clear examples and recommended fixes.
In Python, a "trap" is code that appears to work but behaves unexpectedly; errors that raise exceptions immediately, like UnboundLocalError, are not considered traps.
1. Mutable objects as default arguments
Using a mutable object (e.g., a list) as a default parameter causes the same object to be shared across calls, leading to surprising results.
def f(lst=[]):
lst.append(1)
return lst
print(f()) # [1]
print(f()) # [1, 1] – the list persisted between callsThe standard solution is to use None as the default and create a new object inside the function.
def f(lst=None):
if lst is None:
lst = []
lst.append(1)
return lst2. x += y vs x = x + y
These statements look equivalent, but for mutable objects they differ: x += y modifies the object in place, while x = x + y creates a new object.
x = [1]
x += [2]
print(x) # [1, 2] – same list object
x = [1]
x = x + [2]
print(x) # [1, 2] – a new list object3. Tuple parentheses
Parentheses create a tuple, but a single‑element tuple requires a trailing comma.
a = (1, 2)
print(type(a)) # <class 'tuple'>
b = (1) # not a tuple, just an int
print(type(b)) # <class 'int'>
c = (1,)
print(type(c)) # <class 'tuple'>4. List of lists (mutable default container)
Creating a list of lists with multiplication shares the same inner list.
a = [[]] * 10
print(a) # all sub‑lists refer to the same object
a[0].append(1)
print(a) # every sub‑list now contains 1Use a list comprehension to generate independent inner lists.
a = [[ ] for _ in range(10)]5. Modifying a list while iterating
Removing items from a list while iterating over it can skip elements because the index continues to increase while the list shrinks.
def modify_lst(lst):
for idx, elem in enumerate(lst):
if elem % 3 == 0:
del lst[idx]A safer approach is to build a new list with a comprehension.
lst = [x for x in lst if x % 3 != 0]6. Closures and lambda late binding
When a lambda captures a loop variable, it sees the final value of that variable (late binding).
def create_multipliers():
return [lambda x: i * x for i in range(5)]
for m in create_multipliers():
print(m(2)) # prints 8 five timesFix by binding the current value as a default argument.
def create_multipliers():
return [lambda x, i=i: i * x for i in range(5)]7. Defining __del__
Objects with a __del__ method can prevent the garbage collector from breaking reference cycles, leading to memory leaks.
"Circular references which are garbage are detected when the cycle detector is enabled, but can only be cleaned up if there are no Python‑level __del__() methods involved."
8. Importing the same module in different ways
Using different import styles (e.g., absolute vs. relative, or modifying sys.path) can load separate module objects, causing state inconsistencies.
# In main.py
from mypackage import mymodule
mymodule.l.append(1)
print(id(mymodule))
# Later, inside a function
import mymodule
print(id(mymodule)) # different ID if imported differently9. Python 2 → 3 migration quirks
rangereturns a list in Python 2 but a lazy range object in Python 3. map, filter, and dict.items() return lists in Python 2 and iterators in Python 3.
10. The Global Interpreter Lock (GIL)
The GIL is a well‑known limitation of CPython that prevents true parallel execution of Python bytecode in multiple threads, affecting CPU‑bound programs.
Understanding these pitfalls helps developers write more reliable Python code and avoid subtle bugs.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
MaGe Linux Operations
Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
