My multiple-inheritance-fu is not strong. I am trying to create a superclass whose __init__ takes an optional named parameter and subclasses of it which also inherit from built-in types. Sadly, I appear to have no idea how to make this work:
>>> class Super(object):
name = None
def __init__(self, *args, name=None, **kwargs):
self.name = name
super().__init__(self, *args, **kwargs)
>>> class Sub(Super, int):
pass
>>> Sub(5)
5
>>> Sub(5, name="Foo")
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
Sub(5, name="Foo")
TypeError: 'name' is an invalid keyword argument for this function
(I’ve also tried it without the super() call, but the result was the same.)
Perhaps someone with better knowledge of multiple inheritance can point me in the right direction?
Update:
Here is the solution I ended up with, based on Alex’s answer.
It’s still a little hacky (by changining __new__‘s signature partway through construction), but it will work as long as the superclass appears in the subclasses’ MROs before the built-in type and defining __new__ this way allows me to make subclasses which work with different built-in types without adding a separate __new__ to each one.
>>> class Super(object):
name = None
def __new__(cls, *args, name=None, **kwargs):
inner = super().__new__(cls, *args, **kwargs)
inner.name = name
return inner
>>> class Sub(Super, int):
pass
>>> Sub(5)
5
>>> Sub(5, name="Foo")
5
>>> _.name
'Foo'
You just cannot pass arbitrary parameters (whether positional or named ones) to an equally arbitrary superclass (i.e., “immediately previous type in the
mroof whatever the current leaf type is”) — most types and classes just don’t accept arbitrary parameters, for excellent reasons too — quoting from the middle of theZen of Python,and in most cases, calling (e.g.)
int(name='booga')would of course be an error.If you want you weirdly-named
class Superto be able to “pass on” arbitrary parameters, you must also ensure that all classes ever used as bases after it can handle that — so, for example,intcan be called with one parameter (or exactly two: a string and a base), so, if it’s absolutely crucial to you thatclass Subcan multiply inherit from the buck-passingSuperand int, you have to field that, e.g.:Note that you must override
__new__, not__init__(it does no harm if you also override the latter, but it’s irrelevant anyway):intis immutable so the value has to be set at__new__time.Now, things like
work. But note that
Xmust subclass fromInt(our__new__-sanitizing version ofint), not fromintitself, which, quite properly, has an unforgiving__new__!-)