Skip to the content.
Common Python Antipatterns and How to Avoid Them | AI Systems Design From Scratch

Connect with Amin Boulouma Official

🏠 Documentation Hub 📝 Engineering Blog 💻 GitHub Repository

Common Python Antipatterns

Amin Boulouma, Software Engineer

Even in a language designed for readability, certain habits can lead to fragile, slow, or unidiomatic code. Recognizing these antipatterns is the first step toward writing professional-grade Python.

1. The “C-Style” Loop

Newcomers often translate C or Java logic directly into Python, ignoring the power of built-in iteration tools.

The Antipattern

# Using index to access list elements
items = ['a', 'b', 'c']
for i in range(len(items)):
    print(items[i])

The Idiomatic Solution

Use direct iteration or enumerate when the index is required:

# Direct iteration
for item in items:
    print(item)

# With index
for i, item in enumerate(items):
    print(f"Index {i}: {item}")

2. The “Broad Exception” Trap

Catching everything is tempting but hides bugs that should be exposed.

The Antipattern

try:
    process_data()
except Exception:
    pass  # Silently ignoring errors

The Idiomatic Solution

Catch specific exceptions and handle them appropriately:

try:
    process_data()
except ValueError as e:
    logger.error(f"Invalid data: {e}")
except ConnectionError:
    retry_connection()

3. Misusing Mutable Default Arguments

This is perhaps the most dangerous Python trap, as the default value is evaluated once at definition time, not at call time.

The Antipattern

def add_item(item, list_obj=[]):
    list_obj.append(item)
    return list_obj

print(add_item(1)) # [1]
print(add_item(2)) # [1, 2] -- Unexpected persistence!

The Idiomatic Solution

Use None as the default value and initialize inside the function:

def add_item(item, list_obj=None):
    if list_obj is None:
        list_obj = []
    list_obj.append(item)
    return list_obj

4. Failing to Use Context Managers

Manually opening and closing files or connections leads to resource leaks.

The Antipattern

f = open('data.txt', 'r')
data = f.read()
# Potential for file to remain open if an error occurs
f.close()

The Idiomatic Solution

Always use the with statement for automatic resource cleanup:

with open('data.txt', 'r') as f:
    data = f.read()
# Automatically closed even if an exception occurs

Summary Checklist

Antipattern Better Approach
range(len(x)) for item in x or enumerate
except Exception: Specific Exception classes
Mutable default args Default to None
Manual .close() with statements (Context Managers)

By avoiding these pitfalls, your Python code becomes more readable, robust, and aligned with the “Pythonic” philosophy.

Connect with Amin Boulouma Official