One of the main takes is "Don't write classes that could just be a function" (stated in the video as "If a class has two methods and one of them is __init__, it doesn't need to be a class"). But given the addition of dataclasses and typing to python in the last 10 years, is this still good advice for code style?
For a more specific example, I'd prefer to defining a "useless" class for the purpose of typing like this:
@dataclass
class FooFuncParams:
bar: str
baz: int
...
def foofunc(params: FooFuncParams):
...
Rather than having to use overly-permissive typing like this: def foofunc(params: Dict[str, Any]):
...
What the talk is discussing is the creation of classes for wrapping related _functionality_, sans state. The class isn't really necessary at that point, so you should just create a module with functions instead of a class.
Even if you do need your related functionality to reference some common state, you still might not need a class, because modules themselves are objects and can hold state.
The point of the talk is not to dissuade you from _ever_ using classes, it's to make you think more judiciouly about adding new classes you probably don't need. Python isn't Java, and you dont need everything to be a class.
I think your example of a dataclass replacing a dict is just fine.
I'd grant though that the single-method class is a special case, even in Java it is tempting to use a Function I've found, however, that the "functional class" often adds more methods and attributes over time. In the case of Python, however, you can write something like def fn():
... fn.someAttribute = ... so you can occasionally tack some extra functionality (say metadata) onto a function that way.
>If a class has two methods and one of them is __init__ it doesn't need to be a class.
That seems like dumb advice to me. I don't use classes often in Python, but when I do it is typically because I have a more complex data set to work with and I don't really need database. Usually this is a class that ONLY has an __init__ function in it. Having data set that is a dictionary with nested dictionaries, with nested arrays ,etc. gets ugly and often you end up with a mess of loops trying to parse the data. I find classes super helpful here and would just instance a bunch of class objects with attributes I need, then put all those objects in a list. You can then iterate over a nice, simple, clean, list of you objects and access any attribute you wish. Without having to do nested loops trying to dig down the the value you want.
If you're looking forward to porting to a more performant language, dict has parity with struct, and vtable dereferencing and polymorphism has performance penalties in say, C++. rust and golang don't really have a robust object implementation so flatter structuring is preferred.