Fundamentals 12 min read

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.

MaGe Linux Operations
MaGe Linux Operations
MaGe Linux Operations
10 Common Python Pitfalls Every Developer Should Avoid

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 calls

The 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 lst

2. 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 object

3. 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 1

Use 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 times

Fix 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 differently

9. Python 2 → 3 migration quirks

range

returns 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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

closuresPitfallspython3-migrationmutable-default-args
MaGe Linux Operations
Written by

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.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.