[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