10

When I create a mixin class that extends the logic of __init__, the regular thing to do is:

class ExtraValuemixin:

    def __init__(self, *args, **kwargs)  -> None:
        super().__init__(*args, **kwargs)
        # some extra initialization
        self._extra_value = 1

    def retrieve_extra_value(self):
        return self._extra_value

However this looks wrong to mypy, as it says:

Too many arguments for "__init__" of "object"

I get it, there's no *args or **kwargs in the object's constructor signature; but this is a mixin, and it relies on its childen's constructors. Ho do I make mypy understand this?

Full example:

class ExtraValuemixin:

    def __init__(self, *args, **kwargs)  -> None:
        super().__init__(*args, **kwargs)
        # some extra initialization
        self._extra_value = 1

    def retrieve_extra_value(self):
        return self._extra_value


class ParentObj:

    def __init__(self, value):
        self.value = value


class ChildObj(ExtraValuemixin, ParentObj):
    pass


obj = ChildObj(value=5)

print(obj.retrieve_extra_value())
kurtgn
  • 8,140
  • 13
  • 55
  • 91
  • 1
    `ExtraValueMixin` has `object` as parent class. It's constructor does not has parameters. So you dont need to call super().__init__() there – user3142459 Nov 12 '18 at 14:28
  • Works on CPython 3.6 – cdarke Nov 12 '18 at 14:32
  • @user3142459 I don't need to call super() for standalone classes, but this is a mixin. It nees a `super()` to trigger MRO. if I remove the super() and run the program, I get an error: `TypeError: __init__() got an unexpected keyword argument 'value'` – kurtgn Nov 13 '18 at 06:33
  • Which version of mypy are you using? In mypy==0.641 I cannot reproduce the error message. – pawelswiecki Nov 13 '18 at 18:11
  • @pawelswiecki I corrected my example (i forgot to add ` -> None` annotation, without it mypy did not see the constructor at all). Try it again with mypy==0.641 now please. – kurtgn Nov 16 '18 at 06:38
  • I workaround that currently through letting the subclasses initialize the attribute (here `self._extra_value = 1`) and just remove the constructor for the Mixin (You do not have to say that this is ugly, but in my case the instance attribute has to be initialized by the subclasses with different values anyway) – F.Raab May 22 '19 at 12:21
  • 2
    A general note for good practice, classes which cannot be initialized (such as Mixins) should be marked abstract `class ClassMixin(metaclass=abc.ABCMeta)`. – F.Raab May 22 '19 at 12:24

1 Answers1

1
super().__init__(...)

Calls the __init__ function of it's parent class.


Defining a class with

class XXX:

(Omitting the hierarchal parent), leaves the parent as the default: our friend and beloved object class.

And we know the source of that class looks like:

class object:
    def __init__():

Meaning, that it accepts no arguments. You essentially called this __init__ with two arguments. Hence, your exact error of:

Too many arguments for "__init__" of "object"
rnath
  • 146
  • 5