Fundamentals 8 min read

10 Common Python Anti‑Patterns and How to Avoid Them

This article examines ten frequent Python anti‑patterns—such as mutable default arguments, catching broad exceptions, overly long functions, reinventing the wheel, misusing list comprehensions, excessive lambdas, hard‑coded values, ignoring virtual environments, overusing inheritance, and neglecting code formatting—explaining why they harm readability, maintainability or performance and offering clear, better‑practice alternatives.

Code Mala Tang
Code Mala Tang
Code Mala Tang
10 Common Python Anti‑Patterns and How to Avoid Them

Python is an elegant language—concise, readable, and powerful—but it can also lead to poor code. Both beginners and experienced developers easily fall into common traps that silently degrade code quality.

In this article we explore 10 Python anti‑patterns—coding habits and structures that work but sacrifice readability, maintainability, or performance. We’ll ensure we don’t unintentionally sabotage our code.

1. Using mutable default arguments

<code>def append_to_list(value, my_list=[]):
    my_list.append(value)
    return my_list
</code>

Why it’s bad: The default list is shared across function calls, leading to unexpected behavior.

Better practice:

<code>def append_to_list(value, my_list=None):
    if my_list is None:
        my_list = []
    my_list.append(value)
    return my_list
</code>

Never use mutable objects like lists or dictionaries as default parameter values.

2. Catching broad exceptions

<code>try:
    do_something()
except Exception:
    pass
</code>

Why it’s bad: It catches all exceptions, including those you might not want to ignore, making debugging difficult.

Better practice:

<code>try:
    do_something()
except ValueError:
    handle_value_error()
</code>

Specify the exact exception you intend to handle; only catch all errors when you truly need to record them.

3. Writing long, monolithic functions

A 150‑line function is not something to brag about.

Why it’s bad: Hard to test, understand, and reuse.

Better practice: Break logic into smaller, purpose‑driven functions with descriptive names. Good code reads like a story; modularize your logic.

4. Reinventing the wheel

<code>def is_even(n):
    return n % 2 == 0
</code>

Re‑implementing built‑in functions such as max() , sum() , or writing a custom JSON parser is unnecessary.

Why it’s bad: Python’s standard library is rich; use it instead.

Unless you have a very specific reason, rely on built‑in functions and libraries.

5. Misusing list comprehensions

<code>[print(x) for x in items]
</code>

Why it’s bad: List comprehensions are used for creating lists, not for side effects like printing.

Better practice:

<code>for x in items:
    print(x)
</code>

Use list comprehensions to build lists; use loops for side effects.

6. Overusing lambda functions

<code>sorted(items, key=lambda x: x[1])
</code>

While acceptable, when a lambda starts to look like a mini‑script, refactor it:

<code>key=lambda x: (x[1] * 2 if x[0] == 'foo' else x[1] - 3)
</code>

Better practice:

<code>def custom_sort_key(item):
    if item[0] == 'foo':
        return item[1] * 2
    return item[1] - 3

sorted(items, key=custom_sort_key)
</code>

When a lambda becomes complex, give it a proper function name.

7. Hard‑coding values everywhere

<code>if user_role == "admin":
    # ...
</code>

Why it’s bad: Magic strings and numbers scattered throughout make code fragile.

Better practice:

<code>ADMIN_ROLE = "admin"
if user_role == ADMIN_ROLE:
    # ...
</code>

Using constants makes code self‑documenting and easier to maintain.

8. Ignoring virtual environments

Global package installation? 😬

Why it’s bad: It can pollute the system Python and cause dependency conflicts.

Better practice:

<code>python -m venv venv
source venv/bin/activate
</code>

Always use a virtual environment for project isolation.

9. Overusing inheritance

<code>class Dog(Animal):
    # 100 lines of overridden methods
</code>

Why it’s bad: Inheritance hierarchies can become complex and brittle.

Better practice: Prefer composition over inheritance when it makes sense.

<code>class Dog:
    def __init__(self, walker):
        self.walker = walker
</code>

Inheritance isn’t always the answer; ask yourself if composition fits better.

10. Neglecting code formatting

If you’re still debating spaces vs. tabs in 2025… it’s time to change.

Why it’s bad: Inconsistent formatting wastes review time and causes merge conflicts.

Better practice: Use tools like black , isort , and flake8 to keep code tidy.

<code>black main.py
</code>

Let formatting tools handle style; focus on logic.

Final thoughts

Writing clear, maintainable Python code isn’t about memorizing best practices—it’s about cultivating a mindset of clarity, simplicity, and purpose. These anti‑patterns aren’t unforgivable, but if left unchecked they silently erode code‑base quality.

Pythonsoftware engineeringBest Practicescode qualityanti-patterns
Code Mala Tang
Written by

Code Mala Tang

Read source code together, write articles together, and enjoy spicy hot pot together.

0 followers
Reader feedback

How this landed with the community

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