[Python-ideas] Keyword for direct pass through of kwargs to super

Steven D'Aprano steve at pearwood.info
Sat May 26 04:29:04 EDT 2018

On Sat, May 26, 2018 at 09:39:14AM +0200, Michael Lohmann wrote:
> [Steven D'Aprano]
> >    obj = Aardvark(27, spam=3, eggs=5, cheese=True)
> > 
> > So you look up help(Aardvark), and it tells you that the signature is
> > 
> >    Aardvark.__init__(self, foo)
> > 
> > What the hell? If Aardvark.__init__ only takes a single argument
> This is wrong! This would at some point down the line throw an error
>    TypeError: __init__() got an unexpected keyword argument 'eggs‘

What makes you say that?

Since the kwargs are passed on to the super().__init__ call, the eggs 
argument is passed onto the super class of Aardvark. What makes you so 
certain that Aardvark's parent (or grandparent, or great-grandparent...) 
doesn't take a parameter "eggs"?

Considering that *I* made this example up, it is a bit rich for you to 
tell me that "eggs" isn't used. Of course it is used, by one of the 
superclasses. That's why it was provided.

> (or at some point **kwargs are being accepted and not passed on to 
> super which would be terrible on its own).

No, it is a standard technique to collect keyword arguments, process 
those your class cares about, and pass the rest on to super().

Eventually the class second from the top (the class which inherits 
directly from object) MUST NOT pass those arguments to super, since 
object doesn't accept any arguments: you can't keep passing arguments up 
the MRO all the way to the top. At one point or another, each argument 
must be used and discarded.

> The whole point I was trying to make is: If it doesn’t make any sense 
> to init a class with **kwargs: why write down that it would (or even 
> **could**) accept them? 

If your class doesn't accept **kwargs, then don't put **kwargs in the 
parameter list.

> Shouldn’t the init tell you something like 'If 
> you instantiate this class then this is everything you can give me'? 

The way to do that is to write the __init__ of the class that only takes 
the parameters you want.

> Well, right now in addition it says 'Just give me anything with 
> keywords‘.

Only if you intentionally add **kwargs to the parameter list.

Why are you putting **kwargs in the parameter list if you don't want to 
accept them?

> [Carl Smith]
> > By using **kargs in the constructor and the call
> > to `super`, you are indicating that the signature passes through
> But can you be certain? Couldn’t someone have just used a 
> `kargs.pop('eggs')`?

"Somebody"? Who? It's my class. If "somebody" used kwargs.pop('eggs') 
it must have been me. If I did it, it means that my class wants to 
consume the eggs parameter and NOT pass it on.

> You could argue that they probably wouldn’t 
> have done so. But for making automated documentation it probably would 
> be useful to make sure it didn’t happen.

I don't understand this comment one bit.

> I think that (as Raymond Hettinger once said) 'super is super', but 
> can’t you make it a bit smarter with telling it: 'Hey - If you don’t 
> expect 'eggs', keep calm, it probably (or rather certainly) wasn’t 
> meant for you so just pass it on to your super'.

The way we do that is by explicitly collecting **kwargs and explicitly 
passing it on to the super call.

I don't think I understand the scenario you have in mind. Here is what I 
have in mind:

class Foo:
    def __init__(self, spam):
        self.spam = spam
        # this is a null-op, so it could be left out
        super().__init__()  # calls object.__init__ which does nothing

class Bar(Foo):
    def __init__(self, eggs, **kwargs):
        self.eggs = eggs

class Baz(Bar):
    def __init__(self, cheese, **kwargs):
        self.cheese = cheese
class Aardvark(Baz):
    def __init__(self, myarg, **kwargs):
        self.myarg = myarg

obj = Aardvark(27, spam=3, eggs=5, cheese=True)

What situation do you have in mind?


More information about the Python-ideas mailing list