[Python-ideas] Thread.__init__ should call super()
Steven D'Aprano
steve at pearwood.info
Sat Oct 28 07:14:13 EDT 2017
On Sat, Oct 28, 2017 at 12:14:31AM -0700, Neil Girdhar wrote:
>
>
> On Friday, October 27, 2017 at 8:05:17 PM UTC-4, Steven D'Aprano wrote:
> >
> > On Fri, Oct 27, 2017 at 01:59:01PM -0700, Ilya Kulakov wrote:
> >
> > > Since one of the legit use-cases of using the Thread class is
> > subclassing,
> > > I think it's __init__ should call super() to support cooperative
> > inheritance.
> > >
> > > Or perhaps there is a good reason for not doing so?
> >
> > Are you talking about threading.Thread or some other Thread?
> >
> > If you are talking about threading.Thread, its only superclass is
> > object, so why bother calling super().__init__?
> >
>
> The way cooperative multiple inheritance works is that if someone defines
I didn't realise that Ilya was talking about *multiple* inheritance,
since he didn't use the word, only "cooperative". But since you
are talking about multiple inheritence:
> class SomeClass(Thread):
> def __init__(self, **kwargs):
> super().__init()
>
> they expect this will initialize the base class Thread as desired.
That won't work, since you misspelled __init__ and neglected to pass any
arguments :-) You need:
super().__init__(**kwargs)
otherwise Thread will not be initialised.
> Now, if they add another base class:
>
> class SomeBase:
> def __init__(self, base_x):
> self.base_x = base_x
>
> then they need to pass up the arguments:
>
> class SomeClass(SomeBase, Thread):
> def __init__(self, **kwargs):
> super().__init(**kwargs)
That's not going to work either, because you're passing arguments to
SomeBase that it doesn't understand: all the args that Thread expects.
And of course its going to doubly not work, since SomeBase fails to call
super, so Thread.__init__ still doesn't get called.
If you fix all those problems, you still have another problem: in
Thread, if you call
super().__init__(**kwargs)
then object.__init__ will fail, as I mentioned in my earlier post; but
if you call:
super().__init__()
then object is satisfied, but SomeBase.__init__ gets called with no
arguments. You can't satisfy both at the same time with a single call
to super.
> Unfortunately, if the order of base classes is reversed, this no longer
> works because Thread doesn't call super:
>
> class SomeClass(Thread, SomeBase):
> def __init__(self, **kwargs):
> super().__init(**kwargs) # SomeBase is not initialized!
>
> As things get more complicated it's not always possible to ensure that
> Thread is the last class in the inheritance, e.g., if there are two classes
> like Thread that don't call super.
You can't just add classes willy-nilly into the superclass list. That's
why it is called *cooperative* multiple inheritence: the superclasses
all have to be designed to work together. You *can't* have two classes
that don't call super -- and you must have one class just ahead of
object, to prevent object from receiving args it can't do anything with.
And that class might as well be Thread. At least, I can't think of any
reason why it shouldn't be Thread.
--
Steve
More information about the Python-ideas
mailing list