How do you decide between using decorators and inheritance when both are possible?
E.g., this problem has two solutions.
I'm particularly interested in Python.
The other answers are quite great, but I wanted to give a succinct list of pros and cons.
The main advantage of mixins is that the type can be checked at runtime using isinstance
and it can be checked with linters like MyPy. Like all inheritance, it should be used when you have an is-a relationship. For example dataclass
should probably have been a mixin in order to expose dataclass-specific introspection variables like the list of dataclass fields.
Decorators should be preferred when you don't have an is-a relationship. For example, a decorator that propagates documentation from another class, or registers a class in some collection.
Decoration typically only affects the class it decorates, but not classes that inherit from the base class:
@decorator
class A:
... # Can be affected by the decorator.
class B(A):
... # Not affected by the decorator in most cases.
Now that Python has __init_subclass__
, everything that decorators can do can be done with mixins, and they typically do affect child subclasses:
class A(Mixin):
... # Is affected by Mixin.__init_subclass__.
class B(A):
... # Is affected by Mixin.__init_subclass__.
Mixins have another advantage, which is that they can provide empty base class methods. Child classes can override these methods with some "augmenting" behavior, and then call super. The decorator cannot easily provide such base class methods. This is another way in which mixins are more flexible.
In summary, the questions you should ask when deciding between a mixin and decoration are:
isinstance
?In general, lean towards inheritance.