Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is __init__ a class method?

I was looking into Python's super method and multiple inheritance. I read along something like when we use super to call a base method which has implementation in all base classes, only one class' method will be called even with variety of arguments. For example,

class Base1(object):
    def __init__(self, a):
        print "In Base 1"

class Base2(object):
    def __init__(self):
        print "In Base 2"

class Child(Base1, Base2):
    def __init__(self):
        super(Child, self).__init__('Intended for base 1')
        super(Child, self).__init__()# Intended for base 2

This produces TyepError for the first super method. super would call whichever method implementation it first recognizes and gives TypeError instead of checking for other classes down the road. However, this will be much more clear and work fine when we do the following:

class Child(Base1, Base2):
    def __init__(self):
        Base1.__init__(self, 'Intended for base 1')
        Base2.__init__(self) # Intended for base 2

This leads to two questions:

  1. Is __init__ method a static method or a class method?
  2. Why use super, which implicitly choose the method on it's own rather than explicit call to the method like the latter example? It looks lot more cleaner than using super to me. So what is the advantage of using super over the second way(other than writing the base class name with the method call)
like image 977
thiruvenkadam Avatar asked Feb 18 '15 06:02

thiruvenkadam


People also ask

What type of method is __ init __?

__init__ method "__init__" is a reseved method in python classes. It is called as a constructor in object oriented terminology. This method is called when an object is created from a class and it allows the class to initialize the attributes of the class.

Is __ init __ a instance method?

As for your first question, __init__ is neither a staticmethod nor a classmethod; it is an ordinary instance method.

Is __ init __ a Dunder method?

When you create a new object of a class, Python automatically calls the __init__() method to initialize the object's attributes. Unlike regular methods, the __init__() method has two underscores (__) on each side. Therefore, the __init__() is often called dunder init.

What is __ init __ in Python called?

The purpose of the __init__() method is to initialize the class. It is usually responsible for populating the instance variables. Because of this, you want to have __init__() get called for all classes in the class hierarchy.


2 Answers

super() in the face of multiple inheritance, especially on methods that are present on object can get a bit tricky. The general rule is that if you use super, then every class in the hierarchy should use super. A good way to handle this for __init__ is to make every method take **kwargs, and always use keyword arguments everywhere. By the time the call to object.__init__ occurs, all arguments should have been popped out!

class Base1(object):
    def __init__(self, a, **kwargs):
        print "In Base 1", a
        super(Base1, self).__init__()

class Base2(object):
    def __init__(self, **kwargs):
        print "In Base 2"
        super(Base2, self).__init__()

class Child(Base1, Base2):
    def __init__(self, **kwargs):
        super(Child, self).__init__(a="Something for Base1")

See the linked article for way more explanation of how this works and how to make it work for you!

Edit: At the risk of answering two questions, "Why use super at all?"

We have super() for many of the same reasons we have classes and inheritance, as a tool for modularizing and abstracting our code. When operating on an instance of a class, you don't need to know all of the gritty details of how that class was implemented, you only need to know about its methods and attributes, and how you're meant to use that public interface for the class. In particular, you can be confident that changes in the implementation of a class can't cause you problems as a user of its instances.

The same argument holds when deriving new types from base classes. You don't want or need to worry about how those base classes were implemented. Here's a concrete example of how not using super might go wrong. suppose you've got:

class Foo(object):
     def frob(self):
         print "frobbign as a foo"
class Bar(object):
     def frob(self):
         print "frobbign as a bar"

and you make a subclass:

class FooBar(Foo, Bar):
    def frob(self):
        Foo.frob(self)
        Bar.frob(self)

Everything's fine, but then you realize that when you get down to it, Foo really is a kind of Bar, so you change it

 class Foo(Bar):
     def frob(self):
         print "frobbign as a foo"
         Bar.frob(self)

Which is all fine, except that in your derived class, FooBar.frob() calls Bar.frob() twice.

This is the exact problem super() solves, it protects you from calling superclass implementations more than once (when used as directed...)

like image 155
SingleNegationElimination Avatar answered Oct 04 '22 18:10

SingleNegationElimination


As for your first question, __init__ is neither a staticmethod nor a classmethod; it is an ordinary instance method. (That is, it receives the instance as its first argument.)

As for your second question, if you want to explicitly call multiple base class implementations, then doing it explicitly as you did is indeed the only way. However, you seem to be misunderstanding how super works. When you call super, it does not "know" if you have already called it. Both of your calls to super(Child, self).__init__ call the Base1 implementation, because that is the "nearest parent" (the most immediate superclass of Child).

You would use super if you want to call just this immediate superclass implementation. You would do this if that superclass was also set up to call its superclass, and so on. The way to use super is to have each class call only the next implementation "up" in the class hierarchy, so that the sequence of super calls overall calls everything that needs to be called, in the right order. This type of setup is often called "cooperative inheritance", and you can find various articles about it online, including here and here.

like image 28
BrenBarn Avatar answered Oct 04 '22 17:10

BrenBarn