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

Jacco van Dorp j.van.dorp at deonet.nl
Mon May 28 05:46:46 EDT 2018


2018-05-28 11:07 GMT+02:00 Michael Lohmann <mial.lohmann at gmail.com>:
> But maybe it is just me who thinks that you should make it as obvious as possible what a class itself really can get as an input and what is done just to get the multiple inheritance to work... So I think if no one else agrees with me, we don’t need to further spam everybody.

I think the largest difference is that most people have a different
opinion about what is more explicit/obvious.
It does look like you could build something like this for yourself
with a decorator:

from inspect import signature, Parameter

def forwards_kwargs_to_super(classname):
    def deco(method):
        sig = signature(method)
        numargs = len([param for param in sig.parameters.values() if
param.kind is Parameter.POSITIONAL_ONLY])
        keykwargs = {param.name for param in sig.parameters.values()
if param.kind in (Parameter.POSITIONAL_OR_KEYWORD,
Parameter.KEYWORD_ONLY)}
        def newinit(self, *args, **kwargs):
            print(f"Call looks like: {classname}: {args[:numargs]}, {
{key: val for key, val in kwargs.items() if key in keykwargs} }")
            method(self, *args[:numargs], **{key: val for key, val in
kwargs.items() if key in keykwargs})
            super(globals()[classname],
self).__init__(*args[numargs:], **{key: val for key, val in
kwargs.items() if key not in keykwargs})
        return newinit
    return deco


And then use it like this:

class Aardvark:
    @forwards_kwargs_to_super("Aardvark")
    def __init__(self, quantity):
        print("There is some quantity:", quantity)
        # I actually don’t care about **kwargs and just hand them on

class Clever:
    @forwards_kwargs_to_super("Clever")
    def __init__(self, cleverness=1):
        print("You are %d clever" % cleverness)

class Ethel(Aardvark, Clever):
    """Ethel is a very clever Aardvark"""
    @forwards_kwargs_to_super("Ethel")
    def __init__(self):
        pass

e = Ethel(quantity="some spam", cleverness=100)


Disclaimer:
 - Whenever you import the inspect module, you should ask yourself
whether it's really a good idea.
 - I'm assuming that decorated functions have no *args or **kwargs in
their signature that you DO want to accept, and that all arguments
with a default value are given as keyword arguments.
 - If you are passing new positional arguments with this function, the
subclass positional arguments need to come before the superclass
positional arguments (only important if both have positional
arguments.)
 - If you use multiple decorators, this should be the innermost
decorator, or it'll probably make your code barf at runtime.
 - If you try do this in my company, i'll do whatever I can to get you
fired. For the love of Python, don't use this code at places where
anybody except you has to do maintenance. And if you come back in half
a year and are amazed by your own code, I promise you'll understand
why this might not be a real good solution.
 - Yes, passing your class name and then getting it from globals is an
ugly hack. The alternative is grabbing it from the stack. If anybody
else has a better idea, feel free, but AFAIK it's impossible to do
this better. (I once wrote an overload decorator as a personal
exercise, using the stack hack.)
 - I haven't tested this with actual positional arguments, but I
-think- it will work.


More information about the Python-ideas mailing list