7 ms·
Python classes aren’t always the best solution
- breatheoften 1y agoclasses 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 1y ago> 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 1y ago^ Agreed. And e.g. you can add dataclasses-json for JSON serializability: https://pypi.org/project/dataclasses-json/ https://pypi.org/project/dataclasses-json/
- isjustintime 1y agoYes, dataclasses are great. I often use them as a pretty clear and adopted way to handle serialization and deserialization, configs, etc.
- selfselfgo 1y ago[dead]
- anttiharju 1y agopydantic?
- thenaturalist 1y ago> classes are a bad way to model data imo Genuinely curious: why?
- xigoi 1y agoNot the one you’re replying to, but my take: The main problem with classes is that they conflate a lot of concepts that should be separate and you usually need only one or a few at once, but are 5orced into all of them. Namely: • Product type • Reference semantics • Namespacing • Pipeline-style call syntax • Redefinition of infix operators • Dynamic dispatch • Subtyping For example, you cannot have a product type with value semantics or a type that redefines infix operators but is not a product type.
- Calavar 1y agoYou 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 1y ago> 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 1y agoI 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 1y agoSimilar… Python does look a lot like runable pseudocode. If you already know any type of programming, you might not need a Python class. Haha.
- jollyllama 1y ago> 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.
- fluidcruft 1y agoIt's trivial to subclass dict and list anyway.
- braza 1y agoIt never gets old "Stop Writing Classes"[1] [1] - https://www.youtube.com/watch?v=o9pEzgHorH0 https://www.youtube.com/watch?v=o9pEzgHorH0
- dimatura 1y agoYeah, was going to post this - great talk that I've recommended to incoming devs on our team.
- ravenstine 1y agoOne of my favorites: "Object-Oriented Programming is Bad" https://www.youtube.com/watch?v=QM1iUe6IofM https://www.youtube.com/watch?v=QM1iUe6IofM Followed by "Object-Oriented Programming is Embarrassing: 4 Short Examples". https://www.youtube.com/watch?v=IRTfhkiAqPw https://www.youtube.com/watch?v=IRTfhkiAqPw
- dkarl 1y agoSince 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 1y agoGood 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.
- hidelooktropic 1y agoTrue. Same could be said of namedtuples.
- quietbritishjim 1y agoWow, 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.NamedTuple https://docs.python.org/3/library/typing.html#typing.NamedTu...
- piker 1y ago> 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 1y agotyping.NamedTuple also sets `__slots__ = ()`, just like collections.namedtuple.
- lyu07282 1y ago@dataclass(slots=True) works too
- ok_computer 1y agoAs an aside, my preference for a class container is dataclass(slots=True) for typing. I’d normally used dataclasses as np array containers vs serialized tuple row objects.
- kubb 1y ago
- ozkatz 1y agoI 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 1y agoThe 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 1y agoI 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.
- Arch-TK 1y agoI don't think using TypedDict to create a type hint is against the spirit of the post. Although reading a lot of what has been written here, it seems people aren't really getting the spirit of the post in the first place.
- the__alchemist 1y agoDataclasses are effectively structs.
- rosmax_1337 1y agoI 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 1y agonamedtuple 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 1y agoIt 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.
- sgt 1y agoBut then why not use dataclasses and get constructor, equality etc included?
- stared 1y agoSure, 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/ https://docs.pydantic.dev/latest/concepts/dataclasses/). It can deal with validation when data comes from external sources.
- ackfoobar 1y agoPydantic 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 1y agoClasses 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 1y agoI 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.
- librasteve 1y agoin Raku this is called role composition :-)
- Sohcahtoa82 1y ago> 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.
- 1y ago
- the__alchemist 1y agoData 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 1y agoThis. 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 1y agoThere’s also pyrsistent for immutable data structures with some nice methods for working with them.
- odyssey7 1y agoPython 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 1y agoPython 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.
- odyssey7 1y agoPython is extremely dogmatic in its opinions. Both its objects and its lambdas were intentionally made too difficult to enjoy. There is a depth limit to recursion that is artificially imposed so that programmers will not use recursion. The interface for map is inconvenient. The language’s dogma is pythonic, which was at one time egalitarian, but is now just inconvenient. It is a language that discourages programming.
- CactusQuipster 1y ago[dead]
- deleted 1y ago[deleted]
- tcdent 1y agoRule of thumb: If you find yourself implementing a singleton in Python, you probably wanted a module.
- chaz6 1y agoWho needs a singleton when there is @lru_cache(maxsize=1) /s
- d_burfoot 1y agoFor 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.DataFrame.html https://pandas.pydata.org/docs/reference/api/pandas.DataFram...
- rs186 1y agoI 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.
- hidelooktropic 1y agoTo be clear, "You might not need" does not mean "You shouldn't use"
- samrus 1y agoThe 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?
- hidelooktropic 1y agoCorrect, the examples here are not real. They are examples.
- xigoi 1y ago> No one is so braindead that they would add 2 redundant lines on top of their function def right? Apparently Grant Sanderson (3Blue1Brown), the creator of Manim, is braindead: class ContinuousMotion(Scene): def construct(self): func = lambda pos: np.sin(pos[0] / 2) * UR + np.cos(pos[1] / 2) * LEFT stream_lines = StreamLines(func, stroke_width=2, max_anchors_per_line=30) self.add(stream_lines) stream_lines.start_animation(warm_up=False, flow_speed=1.5) self.wait(stream_lines.virtual_time / stream_lines.flow_speed)
- samrus 1y agoThis isnt the same thing. This is leveraging inheritance. The mathutils example isnt. If the example is supposed to include cases where inheritance is being used and the parent classes methods are important to the child class functioning, then the point in the op is not as valid anymore
- nodesocket 1y agoI’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.
- specproc 1y agoThere just comes a point where they make sense. The article uses some very minimal examples, but the point at which I find myself reaching for classes is the point at which it's gotten complex enough to need them. I find them useful when my code has become a big, sprawling mess of functions throwing dicts around, and I'm losing track of what the structure should be. They're useful when they make sense. I can't think of many projects I've started off with them, but they've helped me straighten a few out. Neither love them nor hate them, and struggle to see why folks get animated about them. They're a useful tool, sometimes.
- gkze 1y agoThis is kind of a poor argument. Its examples are unrealistic, so it’s hard to take the author seriously. It doesn’t delve deep into things like the risks of a strict inheritance hierarchy vs. the benefits of functional composition, or more interesting things like the subtleties of using module-scoped state versus function or class-scoped state. The list goes on. Instead of a slightly dogmatic and mostly unsubstantiated stance, I find less opinionated guidance on what to do when much more helpful. After all the language has all of these constructs for a reason. While I may see a strong argument for a lighter-weight programming model, it is not laid out in this article.
- ac130kz 1y agoApart from dataclasses (which generally should have slots and/or be frozen), this article gives way too much inapplicable advice, which is not scalable even in a small sized project.
- rcarmo 1y agoOne of the things that annoys me about a lot of “modern” Python code is that is reads like Java cosplay: entire classes that are nothing but properties, “helpers” for iteration that make a shambles of ordinary for loops, etc. I have always preferred clean modules and a functional style with well defined signatures, and find it more maintainable to boot.