[Python-ideas] Keyword for direct pass through of kwargs to super
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
> 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
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
> [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
"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:
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
def __init__(self, eggs, **kwargs):
self.eggs = eggs
def __init__(self, cheese, **kwargs):
self.cheese = cheese
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