2

In python 3.3 and later, when we override __new__(), we don't have to pass arguments and keyword arguments to super().__new__() or object.__new__(). But this call to super().__new__() returns an instance of a class.

How does python pass the rest of the arguments to __init__ then?

class Spam(object):
    ''' Hello I am Spam '''

    def __new__(cls, *args, **kwargs):
        print("Creating Instance")
        instance = object.__new__(cls) # Who passed *args and **kwargs to __init__?
        print(instance)
        return instance

    def __init__(self, a, b):
        print("Init Called")
        self.a = a
        self.b = b

Can someone please explain whats happening here?

anthony sottile
  • 61,815
  • 15
  • 148
  • 207
ThinkGeek
  • 4,749
  • 13
  • 44
  • 91
  • Possible duplicate of [Why is \_\_init\_\_() always called after \_\_new\_\_()?](https://stackoverflow.com/questions/674304/why-is-init-always-called-after-new) – anthony sottile Feb 04 '19 at 08:13

2 Answers2

2

You passed cls as an argument to object.__new__, so the interpreter can check whether instance is an instance of cls.

The initializer (__init__) is automatically called by the allocator (__new__) as [Python.Docs]: object.__new__(cls[, ...]) states (emphases are mine):

If __new__() returns an instance of cls, then the new instance’s __init__() method will be invoked like __init__(self[, ...]), where self is the new instance and the remaining arguments are the same as were passed to __new__().

If __new__() does not return an instance of cls, then the new instance’s __init__() method will not be invoked.

code00.py:

#!/usr/bin/env python3

import sys


class Spam(object):
    ''' Hello I am Spam '''

    def __new__(cls, *args, **kwargs):
        print("Creating Instance")
        instance = object.__new__(cls) # Who passed *args and **kwargs to __init__?
        print(instance)
        #return instance  # If you return anything else (1, object(), or None by commenting the line) here, __init__ won't be called
        if len(sys.argv) == 1:  # DO NOT DO THIS!!! It's just for demo purposes
            return instance


    def __init__(self, a, b):
        print("Init Called")
        self.a = a
        self.b = b


def main():
    spam = Spam(1, 2)
    print(type(spam), dir(spam))


if __name__ == "__main__":
    print("Python {0:s} on {0:s}\n".format(sys.version, sys.platform))
    main()

Output:

e:\Work\Dev\StackOverflow\q054511671>"e:\Work\Dev\VEnvs\py_064_03.06.08_test0\Scripts\python.exe" code00.py
Python 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 24 2018, 00:16:47) [MSC v.1916 64 bit (AMD64)] on win32

Creating Instance
<__main__.Spam object at 0x000001F8E24D14E0>
Init Called
<class '__main__.Spam'> ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a', 'b']

e:\Work\Dev\StackOverflow\q054511671>"e:\Work\Dev\VEnvs\py_064_03.06.08_test0\Scripts\python.exe" code.py arg
Python 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 24 2018, 00:16:47) [MSC v.1916 64 bit (AMD64)] on win32

Creating Instance
<__main__.Spam object at 0x0000020808F71550>
<class 'NoneType'> ['__bool__', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

Note that this isn't specific to Python 3 (check [Python 2.Docs]: Data model), but rather to [Python]: New-style Classes For more details, you could also check check [Python 2.2.Docs]: Overriding the __new__ method (the Singleton class).

CristiFati
  • 38,250
  • 9
  • 50
  • 87
  • This is very helpful, thanks for the response. Though I am not sure what is the intent behind this behavior. – ThinkGeek Feb 04 '19 at 08:51
  • What do you mean? It's kind of obvious. The syntax is clearer (simpler for the user). Note that the same thing also works in *Python **2.7.15***. – CristiFati Feb 04 '19 at 09:16
1

What matters here is the initial call, say spam = Spam('x', 1).

Internally, Python calls __new__ as a class method on class Spam with the passed parameters. What Spam.__new__ actually does is not really important, it is just supposed to return an object.

It does use object.__new__ to build a Spam object. As the created object has the correct class, Python calls __init__ on it with the initial parameters.

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • Thanks Serge. The point mentioned by @ChristiFati is really worth understanding. I am not sure how that "return instance" statement is making a difference. Even if it makes a difference what could have been an intent behind that. – ThinkGeek Feb 04 '19 at 08:57