Python: Inherit the superclass __init__

74,604

Solution 1

super(SubClass, self).__init__(...)

Consider using *args and **kw if it helps solving your variable nightmare.

Solution 2

You have to write it explicitly, but on the other hand, if you have lots of args, you should probably use *args for positional args and **kwargs for keyword args.

class SubClass(BaseClass):
    def __init__(self, *args, **kwargs):
        super(SubClass, self).__init__(*args, **kwargs)
        # SubClass initialization code

Another technique you could use is to minimize the code in init and then at the end of init function, call another custom function. Then in the subclass, you just need to override the custom function

class BaseClass(object):
    def __init__(self, *args, **kwargs):
        # initialization code
        self._a = kwargs.get('a')
        ...
        # custom code for subclass to override
        self.load()

    def load():
        pass

class SubClass(BaseClass)
    def load():
        # SubClass initialization code
        ...

Solution 3

If the derived classes don't implement anything beyond what the base class __init__() already does, just omit the derived classes __init__() methods - the base class __init__() is then called automatically.

If, OTOH, your derived classes add some extra work in their __init__(), and you don't want them to explicitly call their base class __init__(), you can do this:

class BaseClass(object):
    def __new__(cls, a, b, c, d, e, f, ...):
        new = object.__new__(cls)
        new._a=a+b
        new._b=b if b else a
        ...
        return new

class A(BaseClass):
    ''' no __init__() at all here '''

class B(BaseClass):
    def __init__(self, a, b, c, d, e, f, ...):
        ''' do stuff with init params specific to B objects '''

Since __new__() is always called automatically, no further work is required in the derived classes.

Solution 4

Perhaps a clearer implementation for your case is using **kwargs combined with new added arguments in your derived class as in:

class Parent:
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c


class Child(Parent):
    def __init__(self, d, **kwargs):
        super(Child, self).__init__(**kwargs)
        self.d = d

By this method you avoid the code duplication but preserve the implicit addition of arguments in your derived class.

Solution 5

Unless you are doing something useful in the subclass __init__() methods, you don't have to override it.

def BaseClass(object):
    def __init__(self, a, b, c, d, e, f, ...):
        self._a=a+b
        self._b=b if b else a
        ...

def A(BaseClass):
    def some_other_method(self):
        pass

def B(BaseClass):
    pass
Share:
74,604
Adam Matan
Author by

Adam Matan

Team leader, developer, and public speaker. I build end-to-end apps using modern cloud infrastructure, especially serverless tools. My current position is R&D Manager at Corvid by Wix.com, a serverless platform for rapid web app generation. My CV and contact details are available on my Github README.

Updated on July 06, 2022

Comments

  • Adam Matan
    Adam Matan almost 2 years

    I have a base class with a lot of __init__ arguments:

    class BaseClass(object):
        def __init__(self, a, b, c, d, e, f, ...):
            self._a=a+b
            self._b=b if b else a
            ...
    

    All the inheriting classes should run __init__ method of the base class.

    I can write a __init__() method in each of the inheriting classes that would call the superclass __init__, but that would be a serious code duplication:

    class A(BaseClass):
        def __init__(self, a, b, c, d, e, f, ...):
            super(A, self).__init__(a, b, c, d, e, f, ...)
    
    class B(BaseClass):
        def __init__(self, a, b, c, d, e, f, ...):
            super(A, self).__init__(a, b, c, d, e, f, ...)
    
    class C(BaseClass):
        def __init__(self, a, b, c, d, e, f, ...):
            super(A, self).__init__(a, b, c, d, e, f, ...)
    
    ...
    

    What's the most Pythonic way to automatically call the superclass __init__?

  • Adam Matan
    Adam Matan almost 13 years
    It helps, but is there a way to completely avoid explicitly calling the superclass init?
  • Paolo Moretti
    Paolo Moretti almost 13 years
    @Adam Matan No, there isn't. See here why: Why aren't Python's superclass init methods automatically invoked?
  • Adam Matan
    Adam Matan almost 13 years
    @Cat Plus Plus correct, but it still requires the annoying code duplication for every base class.
  • Dog eat cat world
    Dog eat cat world almost 13 years
    Are there any difference from BaseClass.__init__(self,*args,*kwargs) and super(BaseClass, self).__init__(*args,*kwargs) ?
  • eyquem
    eyquem almost 13 years
    Fine method, usefull to know. +1. - By the way, as in the question, the code needs to be corrected: class BaseClass(object) instead of def BaseClass(object)
  • kindall
    kindall almost 13 years
    This is a technique I've used, in some cases going so far as to provide preinit() and postinit() hooks. The return value from preinit() can be saved in a local variable in __init__ and passed to postinit(), which is convenient sometimes.
  • Nick Humrich
    Nick Humrich almost 10 years
    @Dogeatcatworld yes. If you called BaseClass.__init__ inside of BaseClass(): __init__: you would get infinite recursion. super calls the parent class.
  • hBy2Py
    hBy2Py over 8 years
    @kindall I want to write a superclass that does some modest, uniform member checking of subclass instances (viz., that needed member variables exist and have sane contents), as part of their __init__ process. I think this sort of postinit() hook should work perfectly.
  • Massimo Variolo
    Massimo Variolo over 8 years
    improvement: kwargs.get('a', defaultvaluehere) instead of kwargs.get('a')
  • astroboylrx
    astroboylrx over 7 years
    @CatPlusPlus Sorry, I have a very stupid question. In Python 3, how can I use the ellipsis to feed the __init__()? I kept getting errors. When you guys used "...", did you really mean ellipsis in the code or it was just meant to save typing?
  • Kai Wang
    Kai Wang over 5 years
    what if I want to pass new params in class A?
  • Kai Wang
    Kai Wang over 5 years
    all solution should looks like this one.
  • JavNoor
    JavNoor almost 5 years
    Running Child(1, 2, 3, 4) I get TypeError: __init__() takes 2 positional arguments but 5 were given. I suspect this should be *args instead of **kwargs
  • avielbl
    avielbl almost 5 years
    by using args, you might mix between your arguments when calling to your child classes. This is why it is better practice in such situation to use **kw and named arguments
  • SimonN
    SimonN over 3 years
    I like this method, but for me it makes more sense to pass **kwargs to the loader as that way the positional args are reserved for the base class arguments that will exist in every implementation and keyword arguments can be used to pass in arguments specific to any given implementation.