[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)