How can I extend the __init__
of a base class, add more arguments to be parsed, without requiring super().__init__(foo, bar)
in every derived class?
class Ipsum:
""" A base ipsum instance. """
def __init__(self, foo, bar):
self.foo = flonk(foo)
grungole(self, bar)
self._baz = make_the_baz()
class LoremIpsum(Ipsum):
""" A more refined ipsum that also lorems. """
def __init__(self, foo, bar, dolor, sit, amet):
super().__init__(foo, bar)
farnark(sit, self, amet)
self.wibble(dolor)
The purpose of the example is to show that there is significant processing happening in the Ipsum.__init__
, so it should not be duplicated in every sub-class; and the LoremIpsum.__init__
needs the foo
and bar
parameters processed exactly the same as Ipsum
, but also has its own special parameters.
It also shows that, if Ipsum
needs to be modified to accept a different signature, every derived class also needs to change not only its signature, but how it calls the superclass __init__
. That's unacceptably fragile.
Instead, I'd like to do something like:
class Ipsum:
""" A base ipsum instance. """
def __init__(self, foo, bar, **kwargs):
self.foo = flonk(foo)
grungole(self, bar)
self._baz = make_the_baz()
self.parse_init_kwargs(kwargs)
def parse_init_kwargs(self, kwargs):
""" Parse the remaining kwargs to `__init__`. """
pass
class LoremIpsum(Ipsum):
""" A more refined ipsum that also lorems. """
def parse_init_kwargs(self, kwargs):
(dolor, sit, amet) = (kwargs['dolor'], kwargs['sit'], kwargs['amet'])
farnark(sit, self, amet)
self.wibble(dolor)
That has the big advantage that LoremIpsum
need only do the parts that are special to that class; handling Ipsum
arguments is handled by that class's __init__
without any extra code.
The disadvantage is obvious, though: this is effectively re-implementing the handling of named parameters by passing a dictionary around. It avoids a lot of repetition, but isn't very clear.
What tools are available to avoid the sub-class definitions always needing to declare the foo
and bar
parameters, and always needing to call super().__init__(foo, bar)
? Those are easy to get wrong, so it would be better if they weren't needed and could just automatically happen, while still allowing LoremIpsum
's customisation of the initialisation.