I've been curious about why both the `dataclasses` module in the standard library and the third-party `attrs` package don't derive from a base class. When you create an object with either of these, there's no straightforward way to check if it's an instance of them besides using specific functions like `dataclasses.is_dataclass()` or catching exceptions. They seem to rely on setting special attributes within their generated classes. Wouldn't it make sense for them to inherit from an abstract base class (ABC) that defines these properties? This way, users could simply use `isinstance` to check classes. Is it performance reasons or something else that led them to avoid this approach?
5 Answers
If you're looking for more insight, the PEP 557 rationale might help clarify this. There was also a really interesting discussion on the attrs GitHub tracker about this topic, but I can't find it now.
I think a mixin could do the job of providing a checkable superclass without much overhead. However, the current construction doesn't seem to warrant that complexity. Honestly, I’m not a fan of how Python handles multiple inheritance either.
Another reason for avoiding a base class is to keep it simple for users managing their own inheritance hierarchies. A base class could complicate the inheritance behavior and create new problems, especially if it has a lot of methods or properties that interfere with existing structures.
That’s a good point! Keeping things straightforward can really help in practical use.
Think of decorators here as macros—they simplify creating more complex class definitions without needing to subclass each time. With that in mind, deriving from a base class could complicate things by forcing you to override many definitions each time or deal with all sorts of additional arguments you may not want.
That makes sense; decorators can streamline the process.
These frameworks mainly add methods to classes instead of changing the underlying type. If you start relying on inheritance, you could run into a ton of issues—like how subclasses behave or deal with `super()` calls. Also, the whole setup could cause problems if a class needs to mix in multiple base classes since Python’s multiple inheritance can be tricky.
Great explanation! I appreciate the clarity.

I get that! It can be confusing sometimes.