# When is \_\_init\_\_ called exactly?

**URL:** <https://discuss.python.org/t/when-is-init-called-exactly/12892>\
**Category:** Python Help\
**Created:** [January 5, 2022, 12:43am UTC](https://discuss.python.org/t/when-is-init-called-exactly/12892 "2022-01-05T00:43:23Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![muntyan](https://avatars.discourse-cdn.com/v4/letter/m/9e8a1a/32.png) [@muntyan](https://discuss.python.org/u/muntyan)\
**Post date:** [January 5, 2022, 12:43am UTC](https://discuss.python.org/t/when-is-init-called-exactly/12892/1 "2022-01-05T00:43:23Z")

</div>

I am trying to understand what is happening in the following code. According to the documentation, `X. __init__ ` is called with the arguments passed to `X()`, but that doesn’t seem to happen here, or there is some magic going on. `X` doesn’t define ` __init__ `, so `object. __init__ ()` should be called, but that isn’t happening because `X(1,2,3)` just works. For comparison, `Y` works as expected, if you pass something to `Y()` then `object. __init__ ` complains that it was given unexpected arguments. Does the presence of ` __new__ ` together with the _absence_ of ` __init__ ` mean something special?

```auto
class X:
    def __new__ (cls, *args, **kwargs):
        return super(). __new__ (cls)

class Y:
    def __new__ (cls, *args, **kwargs):
        return super(). __new__ (cls)
    def __init__ (self, *args, **kwargs):
        return super(). __init__ (*args, **kwargs)

```

```auto
>>> X(1,2,3)
< __main__.X object at 0x000001CCD54AEDC0>
>>> Y(1,2,3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in __init__
TypeError: object. __init__ () takes exactly one argument (the instance to initialize)

```

---

<div class="post-metadata">

**Author:** ![TobiasHT](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/tobiasht/32/23304_2.png) [@TobiasHT](https://discuss.python.org/u/TobiasHT)\
**Post date:** [January 5, 2022, 1:44am UTC](https://discuss.python.org/t/when-is-init-called-exactly/12892/2 "2022-01-05T01:44:57Z")

</div>

There are two methods involved during class instantiation, namely; “ **new** ” and “ **init** ”.  
“ **new** ” is a static method and it’s called first with the first argument being the class with which a new instance is to be created. After an instance is created by “ **new** ” , the process calls “ **init** ” with the rest of the arguments that were passed to “ **new** ” in order to initialize and return a full instance.

All classes are subclasses of the Object class in Python, and the Object class declares “ **dunder** ” methods that can be overriden, by virtual of X being a default subclass of object class, it means it already has a default “ **init** ” method declared, and that’s why it just works when called. The “ **dunder** ” methods still have to remain in the bounds of the conventions in which they are used. Firstly, an “ **init** ” function is not supposed to return anything.  
Secondly, you’ve called the “super(). **init** ” method and passed in \*args and \*\*kwargs, which calls the “ **init** ” method from the Object class since it’s the direct super class of Y, and that “ **init** ” function only expects one argument, which is the return value of “ **new** ”, and that’s why it’s raising an error.  
So, a better way to have implemented Y is this

```python
class Y:
    @staticmethod
    def __new__ (cls, *args, **kwargs):
        return object. __new__ (cls)

    def __init__ (self, *args, **kwargs):
        #do something with the arguments
        print (args, kwargs)

```

---

<div class="post-metadata">

**Author:** ![muntyan](https://avatars.discourse-cdn.com/v4/letter/m/9e8a1a/32.png) [@muntyan](https://discuss.python.org/u/muntyan)\
**Post date:** [January 5, 2022, 2:07am UTC](https://discuss.python.org/t/when-is-init-called-exactly/12892/3 "2022-01-05T02:07:46Z")

</div>

My question isn’t about `Y`, it’s about `X`: why doesn’t `X(1,2,3)` raise an exception? It doesn’t call `self. __init__ (1,2,3)` because that would be the `object. __init__ `, which doesn’t accept extra arguments. So is ` __init__ ` called here, and if yes then when?

---

<div class="post-metadata">

**Author:** ![TobiasHT](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/tobiasht/32/23304_2.png) [@TobiasHT](https://discuss.python.org/u/TobiasHT)\
**Post date:** [January 5, 2022, 2:12am UTC](https://discuss.python.org/t/when-is-init-called-exactly/12892/4 "2022-01-05T02:12:37Z")

</div>

I’ve edited my answer above to kinda answer that. The actual reason why X works is because it is incomplete. It creates an instance but doesn’t call the initializer because it doesn’t have any. So it return an uninitialized instance and discards the values passed to it which would have been passed to init if it had one.

---

<div class="post-metadata">

**Author:** ![muntyan](https://avatars.discourse-cdn.com/v4/letter/m/9e8a1a/32.png) [@muntyan](https://discuss.python.org/u/muntyan)\
**Post date:** [January 5, 2022, 3:25am UTC](https://discuss.python.org/t/when-is-init-called-exactly/12892/5 "2022-01-05T03:25:04Z")

</div>

`X` is complete, it has ` __init__ ` method inherited from `object`. Anyway, here’s the same thing but with the base class which isn’t `object`:

```auto
>>> class A:
... def __init__ (self):
... print("A. __init__")
... super(). __init__ ()
...
>>> class B(A):
... def __new__ (cls, *args):
... return super(). __new__ (cls)
...
>>> B()
A. __init__
< __main__.B object at 0x000001CCD54C36D0>
>>> B(1,2,3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__ () takes 1 positional argument but 4 were given

```

`B` is quite like `X`, except its base is `A` and not `object`. But both `A` and `object` have ` __init__ ` which takes no extra parameters. It feels like `object. __init__ ` is special, and it’s not actually called in some cases (like in the case of `X`).

---

<div class="post-metadata">

**Author:** ![muntyan](https://avatars.discourse-cdn.com/v4/letter/m/9e8a1a/32.png) [@muntyan](https://discuss.python.org/u/muntyan)\
**Post date:** [January 5, 2022, 3:54am UTC](https://discuss.python.org/t/when-is-init-called-exactly/12892/6 "2022-01-05T03:54:03Z")

</div>

Ok, it’s simple: [cpython/typeobject.c at main · python/cpython · GitHub](https://github.com/python/cpython/blob/main/Objects/typeobject.c#L4460)

`object. __init__ ()` is called for `X` but it doesn’t complain about extra arguments because `X` doesn’t override ` __init__ `. I suppose it’s done this way because reasons.

---

<div class="post-metadata">

**Author:** ![steven.daprano](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/steven.daprano/32/1083_2.png) [@steven.daprano](https://discuss.python.org/u/steven.daprano)\
**Post date:** [January 5, 2022, 8:53am UTC](https://discuss.python.org/t/when-is-init-called-exactly/12892/7 "2022-01-05T08:53:51Z")

</div>

Hi TobiasHT,

You don’t need to decorate ` __new__ ` with staticmethod, it is  
automatically done by the compiler. The ` __new__ ` method is special and  
always converted to a static method.

[3. Data model — Python 3.10.1 documentation](https://docs.python.org/3/reference/datamodel.html#object). **new**

---

<div class="post-metadata">

**Author:** ![TobiasHT](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/tobiasht/32/23304_2.png) [@TobiasHT](https://discuss.python.org/u/TobiasHT)\
**Post date:** [January 5, 2022, 9:34am UTC](https://discuss.python.org/t/when-is-init-called-exactly/12892/8 "2022-01-05T09:34:59Z")

</div>

Oh yeah, I get that. But when I’m writing code that is going to be used or worked upon by other Devs, I usually like being detailed in such a way.  
If I’m working on something of my own, I would leave all that out.

It’s just a force of habit 😅

---

<div class="post-metadata">

**Author:** ![TeamSpen210](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/teamspen210/32/1004_2.png) [@TeamSpen210](https://discuss.python.org/u/TeamSpen210)\
**Post date:** [January 5, 2022, 9:50am UTC](https://discuss.python.org/t/when-is-init-called-exactly/12892/9 "2022-01-05T09:50:42Z")

</div>

What that code does is permit and ignore any arguments, if `object. __init__ ` gets called on a subclass. This is done for your convenience, so you don’t need to override ` __init__ ` if you’re only wanting to do things in ` __new__ ` or vice versa.

---

<div class="post-metadata">

**Author:** ![tjreedy](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/tjreedy/32/137_2.png) [@tjreedy](https://discuss.python.org/u/tjreedy)\
**Post date:** [January 6, 2022, 8:43am UTC](https://discuss.python.org/t/when-is-init-called-exactly/12892/10 "2022-01-06T08:43:51Z")

</div>

Tobias. To have double underscores displayed and quoted correctly, use a single backtic like so, `` __new__ ``, and the result will be correct, ` __new__ `. (Note that I added extra escaped backtics to make the text look like what you should type.)

---

<div class="post-metadata">

**Author:** ![TobiasHT](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/tobiasht/32/23304_2.png) [@TobiasHT](https://discuss.python.org/u/TobiasHT)\
**Post date:** [January 6, 2022, 9:49am UTC](https://discuss.python.org/t/when-is-init-called-exactly/12892/11 "2022-01-06T09:49:34Z")

</div>

Thanks for the tip. Actually, I wrote that all on my phone, kinda like how I’m doing with this one, of which the phone was displaying one screen. I had no idea that my double underscores were turning bold until I posted. I did have a feeling that the underscores would turn my comments bold, so I applied the quotes and assumed it would neutralize the effect, guess I thought wrong. Thanks though, we learn something new every day 😊
