146

I was reading 'Dive Into Python' and in the chapter on classes it gives this example:

class FileInfo(UserDict):
    "store file metadata"
    def __init__(self, filename=None):
        UserDict.__init__(self)
        self["name"] = filename

The author then says that if you want to override the __init__ method, you must explicitly call the parent __init__ with the correct parameters.

  1. What if that FileInfo class had more than one ancestor class?
    • Do I have to explicitly call all of the ancestor classes' __init__ methods?
  2. Also, do I have to do this to any other method I want to override?
Eugene S
  • 6,709
  • 8
  • 57
  • 91
liewl
  • 4,021
  • 13
  • 46
  • 65

5 Answers5

177

The book is a bit dated with respect to subclass-superclass calling. It's also a little dated with respect to subclassing built-in classes.

It looks like this nowadays:

class FileInfo(dict):
    """store file metadata"""
    def __init__(self, filename=None):
        super(FileInfo, self).__init__()
        self["name"] = filename

Note the following:

  1. We can directly subclass built-in classes, like dict, list, tuple, etc.

  2. The super function handles tracking down this class's superclasses and calling functions in them appropriately.

Andrew Palmer
  • 2,693
  • 2
  • 13
  • 14
S.Lott
  • 384,516
  • 81
  • 508
  • 779
  • 5
    should i look for a better book/tutorial? – liewl Apr 15 '09 at 20:54
  • 2
    So in the case of multiple inheritance, does super() track them all down on your behalf? – Dana Apr 15 '09 at 20:54
  • dict.__init__(self), actually, but nothing's wrong with it - the super(...) call just provides a more consistent syntax. (I'm not sure how it works for multiple inheritance, I think it may only find one superclass __init__) – David Z Apr 15 '09 at 21:47
  • 4
    The intention of super() is that it handles multiple inheritance. The disadvantage is, that in practice multiple inheritance still breaks very easily (see – sth Apr 15 '09 at 22:06
  • 2
    Yes, in case of multiple inheritance and base classes taking constructor arguments, you usually find yourself calling the constructors manually. – Torsten Marek Apr 15 '09 at 22:53
  • @bullettime: you can try mine -- it might not be enough better -- but here it is: http://homepage.mac.com/s_lott/books/python.html – S.Lott Apr 15 '09 at 23:09
  • @S.Lott: Http/1.1 Service Unavailable - correct your link and will remove this – Mr_and_Mrs_D Jan 05 '14 at 14:20
  • Is it correct to call super's __init__() with no parameters? I thought the correct would be super(FileInfo,self).__init__(**self**) – fonini Dec 22 '15 at 23:57
  • I tried such syntax to subclass another class, but it throws an attribute error saying my class object has not an attribute which is actually created in superclass. Can someone explain what's wrong there please? – Ando Jurai Sep 15 '17 at 08:32
22

In each class that you need to inherit from, you can run a loop of each class that needs init'd upon initiation of the child class...an example that can copied might be better understood...

class Female_Grandparent:
    def __init__(self):
        self.grandma_name = 'Grandma'

class Male_Grandparent:
    def __init__(self):
        self.grandpa_name = 'Grandpa'

class Parent(Female_Grandparent, Male_Grandparent):
    def __init__(self):
        Female_Grandparent.__init__(self)
        Male_Grandparent.__init__(self)

        self.parent_name = 'Parent Class'

class Child(Parent):
    def __init__(self):
        Parent.__init__(self)
#---------------------------------------------------------------------------------------#
        for cls in Parent.__bases__: # This block grabs the classes of the child
             cls.__init__(self)      # class (which is named 'Parent' in this case), 
                                     # and iterates through them, initiating each one.
                                     # The result is that each parent, of each child,
                                     # is automatically handled upon initiation of the 
                                     # dependent class. WOOT WOOT! :D
#---------------------------------------------------------------------------------------#



g = Female_Grandparent()
print g.grandma_name

p = Parent()
print p.grandma_name

child = Child()

print child.grandma_name
Adam
  • 3,675
  • 8
  • 45
  • 77
Code Bug
  • 273
  • 2
  • 5
  • 4
    It doesn't seem like the for loop in `Child.__init__` is necessary. When I remove it from the example I child still prints "Grandma". Isn't grandparent init handled by the `Parent` class? – Adam Apr 30 '14 at 22:17
  • 4
    I think granparents init's are already handled by Parent's init, aren't they? – johk95 Dec 14 '14 at 16:33
18

You don't really have to call the __init__ methods of the base class(es), but you usually want to do it because the base classes will do some important initializations there that are needed for rest of the classes methods to work.

For other methods it depends on your intentions. If you just want to add something to the base classes behavior you will want to call the base classes method additionally to your own code. If you want to fundamentally change the behavior, you might not call the base class' method and implement all the functionality directly in the derived class.

sth
  • 222,467
  • 53
  • 283
  • 367
  • 4
    For technical completeness, some classes, like threading.Thread, will throw gigantic errors if you ever try to avoid calling the parent's __init__. – David Berger Apr 15 '09 at 21:39
  • 6
    I find all this "you don't have to call the base's constructor" talk extremely irritating. You don't have to call it in any language I know. All of them will screw up (or not) in much the same way, by not initializing members. Suggesting not to initialize base classes is just wrong in so many ways. If a class does not need initialization now it will need it in the future. The constructor is part of the interface of the class structure/language construct,and should be used correctly. It's correct use is to call it sometime in your derived's constructor. So do it. – AndreasT Jun 05 '13 at 21:29
  • 2
    "Suggesting not to initialize base classes is just wrong in so many ways." No one has suggested to not initialize the base class. Read the answer carefully. It's all about intention. 1) If you want to leave the base class' init logic as is, you don't override init method in your derived class. 2) If you want to extend the init logic from the base class, you define your own init method and then call base class' init method from it. 3) If you want to replace base class' init logic, you define your own init method while not calling the one from the base class. – wombatonfire Jul 09 '18 at 18:16
  • @AndreasT retrobump, I know, but some languages force you to do it, notably Java. In Java, for example, the language implicitly calls `super();` unless you explicitly call it or another constructor, and if it cannot it produces a compiler error. – Leo Izen Aug 15 '21 at 19:37
4

If the FileInfo class has more than one ancestor class then you should definitely call all of their __init__() functions. You should also do the same for the __del__() function, which is a destructor.

Peter Trcka
  • 1,279
  • 1
  • 16
  • 21
moinudin
  • 134,091
  • 45
  • 190
  • 216
2

Yes, you must call __init__ for each parent class. The same goes for functions, if you are overriding a function that exists in both parents.

vezult
  • 5,185
  • 25
  • 41