Why I Stopped Using Classes in Python (And What I Use Instead)

After years of writing class-based Python code, I realized simpler tools often get the job done better. Here’s what I switched to — and…

Why I Stopped Using Classes in Python (And What I Use Instead)
Photo by NEOM on Unsplash

OOP isn’t always the answer.

Why I Stopped Using Classes in Python (And What I Use Instead)

After years of writing class-based Python code, I realized simpler tools often get the job done better. Here’s what I switched to — and why you might want to as well.

There was a time when I wrapped everything in classes.
It felt like the “professional” thing to do. After all, object-oriented programming (OOP) was the gold standard, right?

But after building APIs, automation scripts, and data pipelines for real-world products, I had a realization: I didn’t need classes as often as I thought.

In fact, in many projects, classes were slowing me down.

Let me explain.

The Class Obsession (And Where It Came From)

Most of us were taught that classes are the foundation of clean, scalable code.
You learn about __init__, inheritance, encapsulation — and before long, you're building elaborate class hierarchies for every little task.

I did this too. My code was filled with boilerplate like:

class User: 
    def __init__(self, name, email): 
        self.name = name 
        self.email = email

But as my projects grew, something didn’t feel right.

Classes added ceremony. They made the simple feel complicated.
Even worse, they sometimes hid the logic behind unnecessary abstraction.


So What’s the Alternative?

Here’s what I started using instead:

1. Functions First

If something doesn’t need to hold state between calls, it doesn’t need a class.
I now write plain functions by default:

def send_email(to, subject, body): 
    # Simple and clear 
    pass

It’s faster to read, test, and reason about.

2. Dataclasses Instead of Classes

If I just need to store data, Python’s @dataclass is a beautiful solution:

from dataclasses import dataclass 
 
@dataclass 
class User: 
    name: str 
    email: str

Less boilerplate
Built-in methods (__init__, __repr__, etc.)
Still readable and lightweight

I use dataclasses for DTOs (Data Transfer Objects), configs, and structured inputs.

3. Dictionaries for Lightweight State

Sometimes, I don’t even need a class or a dataclass.
A good old Python dict does the trick:

user = { 
    "name": "Aashish", 
    "email": "aashish@example.com" 
}

This is especially handy when working with JSON, API responses, or configs.

4. Modules as Singletons

For shared state or utilities, I just use modules — no need to wrap everything in singleton classes.

# email_utils.py 
def send_email(to, subject, body): 
    pass 
 
# usage 
import email_utils 
email_utils.send_email(...)

No class, no unnecessary instantiation — just clean, flat code.


The Problem With Premature Abstraction

Here’s the core issue:
Classes often introduce abstraction before it’s needed.

They make your code:

  • Harder to test (“Do I mock the class or the method?”)
  • More verbose
  • Less Pythonic

I’ve found that sticking to Python’s strengths — simplicity, readability, explicitness — usually leads to better code.

In many scripts, microservices, or ETL jobs, classes are just overkill.

When I Still Use Classes (Because Yes, They’re Still Useful)

I’m not anti-class. I’m anti-default-to-class.

I still use classes when:

  • I need inheritance or polymorphism
  • I’m building complex GUIs or games (e.g., with PyQt or Pygame)
  • I’m using frameworks that require classes (like Django or FastAPI)
  • The object has mutable state and rich behavior

But in my day-to-day work — functions, scripts, APIs — those cases are rare.

Real-World Example: Refactoring Away from Classes

Here’s a real refactor I did in a script that posted Slack messages based on CI events.

Before (class-based):

class SlackNotifier: 
    def __init__(self, webhook_url): 
        self.webhook_url = webhook_url 
 
    def send(self, message): 
        # send message to Slack

After (function-based):

def send_slack_message(webhook_url, message): 
    # send message to Slack

The new version was shorter, easier to test, and didn’t require instantiating a class just to call one method.


Final Thoughts

Python gives us so many expressive tools — we don’t have to reach for classes every time.

Ask yourself:

Does this really need to be a class?

If not, skip it.
Your future self (and your teammates) will thank you.

Photo by Linus Nylund on Unsplash

A message from our Founder

Hey, Sunil here. I wanted to take a moment to thank you for reading until the end and for being a part of this community.

Did you know that our team run these publications as a volunteer effort to over 200k supporters? We do not get paid by Medium!

If you want to show some love, please take a moment to follow me on LinkedIn, TikTok and Instagram. And before you go, don’t forget to clap and follow the writer️!