[HN Gopher] Python classes aren't always the best solution
___________________________________________________________________
Python classes aren't always the best solution
Author : hidelooktropic
Score : 62 points
Date : 2025-07-24 19:41 UTC (3 hours ago)
(HTM) web link (adamgrant.micro.blog)
(TXT) w3m dump (adamgrant.micro.blog)
| breatheoften wrote:
| classes are a bad way to model data imo
|
| I wish python had a clean way to define types without defining
| classes. Think a _good_ mechanism to define the shape of data
| contained within primitives/builtins containers without classes
| -- ala json/typescript (ideally extended with ndarray and a sane
| way to represent time)
|
| Python classes wrapped around the actual "data" are sometimes
| necessary but generally always bad boilerplate in my experience.
| simonw wrote:
| > I wish python had a clean way to define types without
| defining classes
|
| dataclasses are pretty much that. They use the class mechanism
| but they're culturally accepted now as a clean way to build the
| equivalent of structs.
| paulddraper wrote:
| ^ Agreed.
|
| And e.g. you can add dataclasses-json for JSON
| serializability: https://pypi.org/project/dataclasses-json/
| anttiharju wrote:
| pydantic?
| thenaturalist wrote:
| > classes are a bad way to model data imo
|
| Genuinely curious: why?
| Calavar wrote:
| You can use classes withput doing full blown OO. Classes are not
| only for encapsulating data with behavior or code reuse through
| inheritance hierachies. Sure, you can use them for that, but you
| can also use them for code as documentation.
|
| IMHO using adhoc data structures like dicts and named tuples is
| schemaless programming - the equivalent of choosing MongoDB over
| a SQL database, but without any of the performance arguments.
| It's fine for small one off scripts, but as your software's
| complexity grows the implicit (and often entirely undocumented)
| schema turns into tech debt.
| cjs_ac wrote:
| > It's fine for small one off scripts, but as your software's
| complexity grows the implicit (and often entirely undocumented)
| schema turns into tech debt.
|
| It's a great way to start off a project, when you're still
| filling in the details of how everything will fit together.
| Once you've worked out what the schema is, then you can
| solidify it into classes.
| echelon_musk wrote:
| I thought this was going to about how one won't need to take a
| class to learn Python in the inevitable AI future.
| bee_rider wrote:
| Similar... Python does look a lot like runable pseudocode. If
| you already know any type of programming, you might not need a
| Python class. Haha.
| hooverd wrote:
| Python is deceptively simple looking.
| jollyllama wrote:
| > Managing State with Simple Structures: Use Dictionaries or
| Lists
|
| This is bad advice because you wind up hardcoding (or using vars
| for your key names, slightly better) your behavior on the state
| of the dict. Seriously, why not just make a class? You get better
| IDE and possibly better LLM support.
| braza wrote:
| It never gets old "Stop Writing Classes"[1]
|
| [1] - https://www.youtube.com/watch?v=o9pEzgHorH0
| dimatura wrote:
| Yeah, was going to post this - great talk that I've recommended
| to incoming devs on our team.
| ravenstine wrote:
| One of my favorites:
|
| "Object-Oriented Programming is Bad"
|
| https://www.youtube.com/watch?v=QM1iUe6IofM
|
| Followed by "Object-Oriented Programming is Embarrassing: 4
| Short Examples".
|
| https://www.youtube.com/watch?v=IRTfhkiAqPw
| dkarl wrote:
| Since this seems to be a guide for programmers new to Python, I
| wish it made it clear that dataclasses _are_ classes; @dataclass
| just provides a concise way of defining classes with default
| functionality for instance construction, equality, hash, and
| string representation.
|
| Otherwise, this is a decent set of reminders for programmers
| coming from more class-oriented languages.
| smartscience wrote:
| Good point. I wasn't sure from the given examples that overuse
| of classes in this way was all that harmful, e.g. the
| performance penalty hopefully shouldn't be all that
| significant. But then I remembered all the Python code I've
| seen that was obviously written by capable and experienced C++
| programmers.
| quietbritishjim wrote:
| Wow, that is an impressively uninsightful article.
|
| Apart from the first option, all of those are _really obviously_
| not classes.
|
| The first option is a suggestion to use named tuples or
| dataclasses. That is sensible, but you _are_ using a class in
| that case - those are just helpers for making them. You can even
| add your own methods to dataclasses.
|
| For named tuples, you are better off using the typed version
| typing.NamedTuple [1] instead of the classical one suggested in
| the article. Aside from providing typing, the typed version has a
| much nicer syntax to define it and lets you add methods (like
| dataclasses but unlike classical named tuples)
|
| [1]
| https://docs.python.org/3/library/typing.html#typing.NamedTu...
| piker wrote:
| > For named tuples, you are better off using the typed version
| typing.NamedTuple [1] instead of the classical one suggested in
| the article. Aside from providing typing, the typed version has
| a much nicer syntax to define it and lets you add methods (like
| dataclasses but unlike classical named tuples)
|
| It's been a while since I worked in python, but aren't the
| original namedtuples populated with __slots__ instead of a
| __dict__ which makes them a much better choice for very very
| large datasets? Albeit at the cost of duck typing.
| auscompgeek wrote:
| typing.NamedTuple also sets `__slots__ = ()`, just like
| collections.namedtuple.
| lyu07282 wrote:
| @dataclass(slots=True) works too
| kubb wrote:
| Chill, people are learning and not everyone has the luxury of
| reading the manual or going to school or using Python at work
| or whatever.
| pydry wrote:
| There is harmful advice in this article. "Just chill and use
| a dict or a namedtuple" leads inexorably to buggy code.
|
| The advice to use dataclasses is good but... dataclasses are,
| um, classes.
| ackfoobar wrote:
| > dataclasses are, um, classes
|
| So is the case when you use `namedtuple`, which creates a
| new class. This is not an interesting gotcha.
|
| Classes (the Python language construct) are how you
| implement records (the language-neutral concept) in Python.
|
| It's ironic that the "There Is Only One Way to Do It"
| language has multiple bad ways to implement records though.
| quietbritishjim wrote:
| Are people really making classes with a single static method
| and nothing else? It just feels like filler material.
| Sohcahtoa82 wrote:
| Yes. They probably learned Java first.
| callc wrote:
| +1. I learned Java first, in school and on my own. I
| needed to unlearn the OOP-first mindset.
| Jtsummers wrote:
| So you actually thought you needed, in Python, classes
| with static methods instead of just plain old modules?
| What was your first Python "hello world" like?
| dang wrote:
| Sorry to pile on (to
| https://news.ycombinator.com/item?id=44676030), but can you
| please make your substantive points without putting others
| down, or their work? It's always possible to do so, and much
| more in keeping with the spirit we want here:
| https://news.ycombinator.com/newsguidelines.html.
|
| It's great if you know more than others and have time to share
| some of what you know in the comments. But the putdown aspect
| is unnecessary and can really hit people hard sometimes.
| ozkatz wrote:
| I agree grouping behaviors (functions) doesn't require classes,
| but since Python does not have structs, classes are the only way
| to provide types (or at least type hints) for non-scalar data.
| Dicts can only have a key type and value types, while
| lists/tuples can only carry one type. class
| Person: age: int name: str
|
| Would have to be boiled down to `dict[str, Any]` (or worse,
| `tuple[Any]`). You _could_ use `typing.NamedTuple` without
| defining a class (`NamedTuple( 'Person', [('name', str), ('age',
| int)])`) - but subjectively, this is much less readable than
| simply using a data class.
| Arch-TK wrote:
| The typing argument no longer holds. There are typed dicts
| where you specify field names and the respective key types. But
| in most cases you're still best off with just a dataclass. Bare
| classes shouldn't be the first thing you reach for when you
| want structure.
| ozkatz wrote:
| I agree dataclasses are a better alternative when you want a
| class that represents data :)
|
| > There are typed dicts where you specify field names and the
| respective key types
|
| The only way to achieve this that I'm aware of is PEP 589:
| subclassing TypedDict. Which I believe negates the argument
| in the post.
| rosmax_1337 wrote:
| I fail to see any argument why the namedtuple beats the usage of
| a class here. A class in a development view of the problem, is
| also a structure to build and expand upon, a tuple is a promise
| this won't be expanded upon. Clearly case dependent which is
| better.
| JohnKemeny wrote:
| namedtuple is not a replacement for a class, but for a tuple.
| It is a tuple with named accessors.
|
| You can also argue that you don't need a Pair type since you
| can simple make a class for the two things you want to contain.
| SamuelAdams wrote:
| It also makes the code easier to read, and that is what our org
| optimizes for, all else being equal. Code is read 10x more than
| it is modified, so if you can make it a little quicker to
| understand it's generally recommended.
| stared wrote:
| Sure, some people use classes when all they need is a namespace -
| and for that having a file is enough.
|
| If there is a collection of related data, it is (often) good to
| have it as a class. In the config example, a class may work
| better - as then you can pass it as an argument somewhere.
|
| At the same time, in many cases, instead of a dataclass, it is
| worth considering Pydantic
| (https://docs.pydantic.dev/latest/concepts/dataclasses/). It can
| deal with validation when data comes from external sources.
| ackfoobar wrote:
| Pydantic is everything I want Python dataclasses to be.
|
| While Pydantic `BaseModel`s, like dataclasses, are still
| "classes", I consider that an implementation detail of how
| records are implemented in Python - thus not really
| contradicting the article's recommendation against using a
| class.
| ravenstine wrote:
| Classes aren't outright bad, but I've seen them misused so many
| times that I knee-jerk cringe when I see the keyword `class` in
| any programming language; too often have I seen classes misused
| and misapplied (in my opinion).
|
| If what you're writing is fundamentally a singular self-described
| action, there's almost certainly no reason to apply _thinginess_
| to it. But I see this practice all the time in open-source code,
| and it describes Java to a tee.
|
| Is the mutation of your data best described as a behavior? If
| not, then a simpler data structure and functions that act upon
| that structure may be easier to understand and be more composable
| in the long run.
|
| And _almost never_ use inheritance, especially if that
| inheritance chain goes beyond one ancestor.
|
| I almost never use classes these days. If I were writing a game,
| I imagine that classes would be conceptually helpful in making
| sense of ideas that manifest as _things_ with behavior in a
| virtual world. For general programming tasks, I find them largely
| unhelpful and to be a potential trap.
|
| EDIT: When I said I "almost never" use classes, of course I _do_
| work with classes at my job because it would be obnoxious of me
| to deviate from the collective pattern. With my own personal
| code, the only time I end up using classes is if I 'm forced to
| (ex. web components).
| moomoo11 wrote:
| I use TypeScript a lot recently, and I've been using class with
| static methods. No internal states.
|
| It is more of an organizing decision, and I wanted to avoid DI
| and additional configuration up front. KISS.
| Sohcahtoa82 wrote:
| > And almost never use inheritance, especially if that
| inheritance chain goes beyond one ancestor.
|
| With Python's duck typing, I'm not even sure of a case where
| inheritance is even strictly necessary beyond custom
| exceptions.
| the__alchemist wrote:
| Data classes and enums are the move, IMO, in python, to address
| the considerations of the article. Enums in particular have room
| for improvement, but I think they're good enough. (To use in
| place of common python patterns like strings for choices, or sets
| of booleans)
| danofsteel32 wrote:
| This. You can get very far with just dataclasses, enums, and
| functions. I use dataclasses like I would use structs in C or
| go.
| clickety_clack wrote:
| There's also pyrsistent for immutable data structures with some
| nice methods for working with them.
| odyssey7 wrote:
| Python is neither object-oriented nor functional. It's
| _pythonic_. It was popularized by academia because it's good for
| beginner programming assignments, and unfortunately the legacy of
| object-oriented Python in academia forced ML to inherit it.
| nyrikki wrote:
| Python is a good glue language, which helps with cleaning and
| interfacing with other languages that are more effective in
| specific contexts.
|
| The fact that it isn't dogmatic in it's opinions is a feature
| for the use case.
|
| It isn't great at many things but it can do most things well
| enough.
|
| It's popularity as a teaching language lagged way behind it's
| adoption for real world needs BTW.
| tcdent wrote:
| Rule of thumb:
|
| If you find yourself implementing a singleton in Python, you
| probably wanted a module.
| d_burfoot wrote:
| For people who think classes are terrible, can you explain how
| you would implement the functionality associated with a Pandas
| DataFrame, without using classes? Did the Pandas developers
| simply get it wrong when choosing how to build this?
|
| https://pandas.pydata.org/docs/reference/api/pandas.DataFram...
| rs186 wrote:
| I don't think there are many people that say classes are bad
| outright. After all, you can write Go code that look identical
| to code in another language with classes. It's more about
| misusing OOP and unnecessary amount of abstraction people
| complain about.
|
| Also, patterns in data science often don't transfer to general
| programming. Very few data scientists annotate their python
| types, let alone writing unit tests. Source control of Jupyter
| notebooks is often non-existent. It's a different way of doing
| things, and I would exclude numpy/pandas from discussions
| unless necessary.
| samrus wrote:
| The examples provided here cant be real, right? Like look at the
| MathUtils one. No one is so braindead that they would add 2
| redundant lines on top of their function def right?
| nodesocket wrote:
| I'm relative newbie to Python (come from Javascript) but I've
| been building a Flask web app for the last couple of months.
| Almost my entire Flask codebase is just packages with functions.
| There are only a handful of classes and that's because I am
| overriding some Exception classes with custom behavior.
___________________________________________________________________
(page generated 2025-07-24 23:01 UTC)