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

def append_to_list(value, my_list=[]):
    my_list.append(value)
    return my_list

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

Better practice:

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

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

2. Catching broad exceptions

try:
    do_something()
except Exception:
    pass

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

Better practice:

try:
    do_something()
except ValueError:
    handle_value_error()

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

def is_even(n):
    return n % 2 == 0

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

[print(x) for x in items]

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

Better practice:

for x in items:
    print(x)

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

6. Overusing lambda functions

sorted(items, key=lambda x: x[1])

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

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

Better practice:

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

sorted(items, key=custom_sort_key)

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

7. Hard‑coding values everywhere

if user_role == "admin":
    # ...

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

Better practice:

ADMIN_ROLE = "admin"
if user_role == ADMIN_ROLE:
    # ...

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:

python -m venv venv
source venv/bin/activate

Always use a virtual environment for project isolation.

9. Overusing inheritance

class Dog(Animal):
    # 100 lines of overridden methods

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

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

class Dog:
    def __init__(self, walker):
        self.walker = walker

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.

black main.py

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.

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.

Pythonsoftware-engineeringcode 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

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.