11

I am having a hard time figuring out the purpose some code that I've come across.

The code has a class Foo, which has an __init__ method that takes multiple arguments. From what I've learned of Python so far, by calling Foo('bar'), it will pass this string as a parameter to __init__ (which I think is supposed to be the equivalent of a constructor).

But the issue I am having is that the code I am looking at is calling Foo.__init__('bar') directly. What is the purpose of this? I almost feel that I am missing some other purpose behind __init__.

nbro
  • 15,395
  • 32
  • 113
  • 196
Ari
  • 3,489
  • 5
  • 26
  • 47

3 Answers3

23

The __init__() method gets called for you when you instantiate a class. However, the __init__() method in a parent class doesn't get called automatically, so need you to call it directly if you want to extend its functionality:

class A:

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

class B(A):

     def __init__(self, x, y):
          A.__init__(self, x)
          self.y = y

Note, the above call can also be written using super:

class B(A):

     def __init__(self, x, y):
          super().__init__(x)
          self.y = y

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.

nbro
  • 15,395
  • 32
  • 113
  • 196
Raymond Hettinger
  • 216,523
  • 63
  • 388
  • 485
  • 1
    In the second example code block, why do you call `super().__init__(x)` in the B constructor instead of calling `(super())(x)`? Maybe this is a separate question, but why doesn't that `__init__` call have B's `self` as its 1st argument? Isn't calling `__init__` only necessary if you need to pass in something to use as a reference to the instance? – iono Feb 04 '21 at 14:30
4

Python allows you to call the constructor (__init__) directly. By calling Foo.__init__(obj, 'bar'), you're doing an initialization/reinitialization of obj

See this code:

class Foo:
    def __init__(self, s):
        self.s = s

f = Foo('abc')
print(f.s) # prints 'abc'
Foo.__init__(f, 'def')
print(f.s) # prints 'def'
aldeb
  • 6,588
  • 5
  • 25
  • 48
  • 9
    Oh dear. Please don't call `__init__` to perform reinitialization in any sane system... – nneonneo Apr 21 '13 at 00:38
  • I agree. Sorry if my explanation is bad. Right now I just wanted to show what `__init__` does. Not where it should be called. – aldeb Apr 21 '13 at 00:39
  • 2
    Saying "`__init__` is not really a constructor, it's rather an initializer" is not helpful. It's something someone wrote in a book once that has become repeated all over the internet, despite the fact that it makes no sense and just confuses people who already know what a constructor is who are learning Python. `__init__` exactly corresponds to constructors from other languages, and the official Python documentation even refers to it as one! If you could call a constructor on an existing object in any other OO language, this is exactly what it would do. – Ben Apr 21 '13 at 02:55
  • 1
    I founded the first answer of this topic that resumes well what I want to tell: http://stackoverflow.com/questions/6578487/init-as-a-constructor. Also `__init__` doesn't "exactly corresponds to constructors from other languages", since you can't write what I wrote above in other languages (AFAIK in c, c++, Java). What I wanted to say is that `__init__` doesn't create a new object, as in other languages, and I think it's useful to know that to understand metaclasses. However I know `__init__` shouldn't be called for that purpose as I said in my previous comment. – aldeb Apr 21 '13 at 08:22
  • @segfolt Java and C++ constructors don't create new objects either. By the time the constructor is invoked, the object is already created (I don't ever recall writing something like `this = malloc(...)` in a constructor; do you?). The purpose of a `__init__` is to operate **on** a "blank" object to initialise the data contained within it, and it's invoked automatically by the object-creation machinery when you call `SomeClass(...)` *after* the object is created but before the `SomeClass(...)` expression returns its value to the caller. Sounds exactly like a Java/C++ constructor to me... – Ben Apr 22 '13 at 03:23
  • @Ben: In fact, you're right that `__init__` sounds like C++/Java constructor, because of what you explained below, excepted perhaps by the small example in my post. Also in C++, what I wanted to say is not that the constructor creates the object, but rather that you can't call a constructor without creating a object. I mean you can only call constructor in object's definition contexts. (for more precision, once againt, I know that most of the time in Python `__init__` is called for object definition. I'm talking about what the language allows you to do. – aldeb Apr 22 '13 at 06:55
  • @segfolt Yep, so that's exactly how I'd put it; Python allows you to call the constructor directly (because `__init__` is an ordinary method), even though you can't directly call constructors in Java/C++ (except from another constructor). Much less confusing than saying that `__init__` isn't really a constructor. – Ben Apr 22 '13 at 07:11
  • @Ben: You're right. See my edited post. Btw: where does the documentation refers to `__init__` as a constructor? – aldeb Apr 22 '13 at 07:49
  • @segfolt Only once that I've found, in the general description of `__init__`. http://docs.python.org/2/reference/datamodel.html#object.__init__ I guess generally the Python docs can just use the name `__init__` to refer to it because it *has* a name, so there's no strong *need* for a term like "constructor" in Python (unlike C++/Java). – Ben Apr 23 '13 at 01:02
0

Yes - when inheriting class invokes __init__() of the parent class. AFAIK, this is the only valid case of calling __init__() explicitly.

nbro
  • 15,395
  • 32
  • 113
  • 196
volcano
  • 3,578
  • 21
  • 28