Composition instead of inheritance
ian.g.kelly at gmail.com
Fri Apr 29 23:44:56 CEST 2011
On Fri, Apr 29, 2011 at 3:09 PM, Carl Banks <pavlovevidence at gmail.com> wrote:
> Here is my advice on mixins:
> Mixins should almost always be listed first in the bases. (The only exception is to work around a technicality. Otherwise mixins go first.)
> If a mixin defines __init__, it should always accept self, *args and **kwargs (and no other arguments), and pass those on to super().__init__. Same deal with any other function that different sister classes might define in varied ways (such as __call__).
Really, *any* class that uses super().__init__ should take its
arguments and pass them along in this manner. This applies to your
base classes as well as your mixins. It's okay to take keyword
arguments as well, but you have to be careful to pass them on exactly
as you received them. Reason being that you can't pragmatically
predict which __init__ method will be invoked next by the super call,
which means that you can't predict which arguments will be needed for
that call, so you just have to pass all of them along.
> A mixin should not accept arguments in __init__. Instead, it should burden the derived class to accept arguments on its behalf, and set attributes before calling super().__init__, which the mixin can access.
Ugh. This breaks encapsulation, since if I ever need to add an
optional argument, I have to add handling for that argument to every
derived class that uses that mixin. The mixin should be able to
accept new optional arguments without the derived classes needing to
know about them.
> If you insist on a mixin that accepts arguments in __init__, then it should should pop them off kwargs. Avoid using positional arguments, and never use named arguments. Always go through args and kwargs.
Theoretically this would break if you had two mixins accepting the
same argument, but I can't think of an actual case where that might
More information about the Python-list