super or not super?

Chris Angelico rosuav at gmail.com
Tue Jul 16 14:31:56 EDT 2019


On Wed, Jul 17, 2019 at 3:58 AM Ian Kelly <ian.g.kelly at gmail.com> wrote:
>
> On Tue, Jul 16, 2019 at 1:21 AM Chris Angelico <rosuav at gmail.com> wrote:
> >
> > On Tue, Jul 16, 2019 at 3:32 PM Ian Kelly <ian.g.kelly at gmail.com> wrote:
> > >
> > > Just using super() is not enough. You need to take steps if you want to
> > > ensure that you class plays nicely with MI. For example, consider the
> > > following:
> > >
> > > class C1:
> > >     def __init__(self, name):
> > >         self._name = name
> > >
> > > class C2(C1):
> > >     def __init__(self, name, value):
> > >         super().__init__(name)
> > >         self._value = value
> > >
> > > This usage of super is just fine for the single-inheritance shown here.
> But
> > > there are two reasons why this cannot be neatly pulled into an MI
> > > hierarchy. Can you spot both of them?
> >
> > Well, obviously it's violating LSP by changing the signature of
> > __init__, which means that you have to be aware of its position in the
> > hierarchy. If you want things to move around smoothly, you HAVE to
> > maintain a constant signature (which might mean using *args and/or
> > **kwargs cooperatively).
>
> That's pretty close to what I had in mind. Many people treat __init__ as a
> constructor (I know, it's not)

If you consider __new__ to be the constructor, and __init__ to be an
implementation detail of how the constructor initializes the object,
then it comes to the same thing anyway.

> and so long as you're following that
> doctrine it's not really an LSP violation. But anything else that gets
> worked into an MI hierarchy has to somehow be compatible with both of these
> method signatures while also adding whatever new parameters it needs, which
> is a problem. The usual advice for working with this is to use **kwargs
> cooperatively as you suggested. *args doesn't work as well because every
> class needs to know the absolute index of every positional parameter it's
> interested in, and you can't just trim off the end as you go since you
> don't know if the later arguments have been consumed yet. With **kwargs you
> can just pop arguments off the dict as you go.

Yeah, makes sense. I'd advocate a slightly weakened form of LSP-style
equivalence: the function signatures don't have to be *identical*, but
they do have to be built with compatibility in mind.

ChrisA



More information about the Python-list mailing list