>       If I understand correctly, the essence of your argument seems to be 
> that you want be able to write a class A, and you want to be able to use that 
> class EITHER as the top of an inheritance chain (i.e., have it inherit 
> directly from object) OR in the middle of an inheritance chain (i.e., 
> inheriting from some other class, but not object).
Well, it does not necessarily inherit from object, but from any class, that 
does not accept any more kwargs. E.g.  if you have a diamond structure as your 
class-hierachy then one branch could forward information to the second (if you 
understand what I mean?).

> But I don't really see how your solution of magically making kwargs appear 
> and disappear is a good solution to that problem.

I intended the following text for the python-list mailing-list, but it I think 
I might have structured my ideas a bit better than in my previous messages and 
the summary in __Reason__ might tackle why this could be a nice idea (spoiler: 
make super even more super by doing things if it is NOT there in a clever 
manner).


Let us start with a simple class:
    class Aardvark:
        def __init__(self, quantity):
            print("There is some quantity:", quantity)


Well, that works nicely and we can go and send our Aardvark to survey some 
quantities. But if we now want to get the multi-inheritance to work properly we 
need to change it to:

    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)

But if you now look at the declaration of the Aardvark .__init__, it seems like 
you could instantiate it with **kwargs. This in fact is not true. As soon as 
you create a direct instance of Aardvark, `object` as the super() doesn’t 
accept any kwargs. So basically I think that the parameters for the init should 
just say `quantity ` while still preserving the functionality.

Now that obviously doesn’t work until now. But could you add something that 
lets this class tell the interpreter instead: "Hey, could you just forward 
anything that this init doesn’t need to super().__init__" ? I have something 
like this in mind:

    class Aardvark:
        @bypass_kwargs_to_super
        def __init__(self, *, quantity):
            print("There is some quantity:", quantity)
            super().__init__()

This would collect everything "behind the scenes" that usually **kwargs would 
have collected and "append" it to the super call. Question: If Aardvark knows 
that he really does not need the kwargs himself: why give them to him in the 
first place? I mean, I trust him - he seems like a very nice guy, but he might 
have accidentally forgotten to forward them unintentionally.

You would obviously still be able to use **kwargs the usual way but then you 
couldn’t use this technique and would need to take care of passing down all the 
information to super() yourself as usual.


__Reason__: With something like this it is immediately obvious that Aardvark 
ONLY takes `quantity` as an input if you instantiate it directly but if 
subclassed it is able to hand information down the MRO to something from a 
different "Branch". And in addition to the better human readability: any form 
of automated docstring-genaration now can be certain that you don’t do anything 
with (or to) the **kwargs (since the init doesn’t get them in the first place). 
In addition it could make super even more super by doing something if it is NOT 
there as proposed in the second of the the following problems.

Of course you need to be quite clever to do this properly, for example
1) What to do if there are collisions between the bypassed kwargs and the ones 
from the init call? - Probably keep the ones you bypassed since they come from 
the top of the MRO
2) What do you do if super().__init__ was not called? The most clever thing 
would be to go „up and to the next branch“ of the inheritance diagram. As in: 
if Aardvark is a Subclass of Animal, don’t call its init but directly Clevers - 
(you would have to look up the MRO of the super of Aardvark and skip them in 
the Ethel MRO before calling the next init automatically).

In theory you could also add something that forwards *args as well but the 
usage of that is probably much more limited...

On thing that might look a bit strange is that you actually could actually pass 
in additional kwargs despite the init saying otherwise:
`Aardvark(quantity='some spam', something="Object will throw an error now 
unexpected kwarg")`
and this would then throw an error that "object (instead of Aardvark) does not 
expect something". But I guess that would be okay since the init now is much 
better readable of what it actually expects.

Michael
_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to