[Python-ideas] Keyword for direct pass through of kwargs to super
Jacco van Dorp
j.van.dorp at deonet.nl
Mon May 28 04:24:08 EDT 2018
2018-05-28 9:44 GMT+02:00 Michael Lohmann <mial.lohmann at gmail.com>:
>
>> I'd say NOT wanting to call an __init__ method of a superclass is a
>> rather uncommon occurence. It's generally a huge error. So I think
>> it's worth not accomodating that.
>
> I will give you an example then where I am absolutely fine with calling super().__init__ in all classes and describe why I am not really satisfied with the current status. (It is from my email from yesterday 17:19 GMT):
>
>> What bugs me is that in my example from yesterday (
>> class Aardvark:
>> def __init__(self, quantity, **kwargs):
>> print("There is some quantity:", quantity)
>> # I actually don’t care about **kwargs and just hand them on
>> super().__init__(**kwargs)
>>
>> class Clever:
>> def __init__(self, cleverness=1):
>> print("You are %d clever“ % cleverness)
>>
>> class Ethel(Aardvark, Clever):
>> """Ethel is a very clever Aardvark"""
>> def __init__(self):
>> super().__init__(quantity="some spam", cleverness=1000)
>> ) if you want to instantiate an Aardvark directly there is NO WAY EVER that you could give him ANY kwargs. So why should the __init__ indicate something else? Well, just to make the MRO work. All I want is to make it as obvious as possible that an Aardvark only takes `quantity` as input, but is fully "cooperative" with other classes if it is in the middle of the MRO (by which I mean that it will automatically call the __init__ and hand on any kwargs it didn’t expect to a class from a different branch of the class hierarchy).
This is more an issue with your Ethel class. In *normal* subclassing,
it's init would look like:
class Ethel(Aardvark, Clever):
def __init__(self, **kwargs):
super().__init__(**kwargs)
and you'd instantiate it like:
e = Ethel(quantity="some spam", cleverness=1000)
or even (because keyword argument order doesn't matter):
e = Ethel(cleverness=1000, quantity="some spam")
Because don't forget:
assert isinstance(e, Ethel)
assert isinstance(e, Aardvark)
assert isinstance(e, Clever)
will all pass perfectly fine. It's not just an Ethel or an Aardvark,
it's also a Clever. (which doesn't sound like it makes sense...perhaps
clever should be an attribute on an Aardvark/Ethel instead ?).
That all aside, for a moment. You actually CAN call
object.__init__(**kwargs) no problem - as long as kwargs is empty. I'd
have written your classes like this:
class Aardvark:
def __init__(self, quantity, **kwargs):
print("There is some quantity:", quantity)
# I actually don’t care about **kwargs and just hand them on
super().__init__(**kwargs)
class Clever:
def __init__(self, cleverness=1, **kwargs):
print("You are %d clever" % cleverness)
super().__init__(**kwargs)
class Ethel(Aardvark, Clever):
"""Ethel is a very clever Aardvark"""
def __init__(self, **kwargs):
super().__init__(**kwargs)
Just try it - it works perfectly fine. Each constructor will consume
the keywords meant for it, therefore, the last super() call will call
the object constructor without keyword arguments.
**kwargs is the price we have to pay for good multiple inheritance -
and IMO, it's a low one.
If we're talking about signalling what the arguments mean, just ensure
you have a good docstring.
class Aardvark:
def __init__(self, quantity, **kwargs):
"""
Aardvarks are gentle creatures, and therefore cooperate with
multiple inheritance.
:param quantity: The quantity of Aardvark(s).
"""
More information about the Python-ideas
mailing list