[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