Loading video player…

Exploring the Instantiation Process

For more information on properties, you can check out Python’s property(): Add Managed Attributes to Your Classes.

00:01 Exploring the Instantiation Process. To explore how Python’s instantiation process works internally, consider the following example of a Point class that implements custom versions of both the .__new__() and .__init__() special methods, for demonstration purposes.

00:20 This line defines the Point class using the class keyword followed by the class name.

00:29 This defines the .__new__() special method, which takes the class as its first argument. Note that using cls as the name of this argument is a strong convention in Python, just like using self to name the current instance is.

00:43 The method also takes *args and **kwargs, which allow for passing an undefined number of initialization arguments to the underlying instance. This line prints a message when .__new__() runs the object creation step.

01:00 This complex-looking line creates a new Point instance by calling the parent class’s .__new__() method with cls as an argument. In this example, object is the parent class, and the call to super() gives you access to it.

01:14 Then the instance is returned. This instance will be the first argument to .__init__(). Here you define .__init__(), which is responsible for the initialization step.

01:26 This method takes a first argument called self, which holds a reference to the current instance. The method also takes two additional arguments, x and y.

01:37 These arguments hold initial values for the instance attributes .x and .y. You need to pass suitable values for these arguments to the call to Point(), as you’ll learn in a moment. These lines print a message when .__init__() runs the object initialization step, and then initialize the .x and .y attributes, respectively. To do this, they use the provided input arguments x and y. Finally, these lines implement the .__repr__() special method, which provides a proper string representation for the Point class.

02:10 With Point in place, you can uncover how the instantiation process works in practice. Save the code to a file called point.py and start a new Python session from a command-line window in the same directory as the code is saved.

02:26 Then run the code seen on-screen.

02:34 Calling the Point() class constructor creates, initializes, and returns a new instance of the class. This instance is then assigned to the variable point.

02:45 In this example, the call to the constructor also lets you know the steps that Python internally runs to construct the instance. First, Python calls .__new__() and then .__init__(), resulting in a new and fully initialized instance of Point, as you confirmed at the end of the example.

03:03 To continue learning about class instantiation in Python, you can try running both steps manually.

03:13 Here, you first call .__new__() on the Point class, passing the class itself as the first argument to the method. This call only runs the first step of the instantiation process, creating a new and empty object. Note that creating an instance this way bypasses the call to .__init__(), and the object is not initialized.

03:34 This can be demonstrated by trying to access the .x and .y attributes, which generate errors. Once you have the new object, then you can initialize it by calling .__init__() with an appropriate set of arguments.

03:52 After this, the Point object is properly initialized, with all of its attributes set up. Note that this code is intended to be a demonstration of how the instantiation process works internally.

04:03 It’s not something that you would typically do in real code. A subtle and important detail to note about the .__new__() special method is that it can also a return an instance of a class different from the class that implements the method itself. When that happens, Python doesn’t call .__init__() in the current class, because there’s no way to unambiguously know how to initialize an object of a different class.

04:29 Next, you’ll see an example of this on-screen, where the .__new__() method of the B class returns an instance of the A class.

05:11 Because B.__new__() returns an instance of a different class, Python doesn’t run B.__init__(). To confirm this behavior, save the code into a file called ab_classes.py and then run the following code in an interactive Python session.

05:32 The call to the B() class instructor runs B.__new__(), which returns an instance of A instead of B. And this is why B.__init__() never runs.

05:44 Note that b doesn’t have a .b_value attribute. In contrast, b does have an .a_value attribute with a value of 42.

05:54 This instance can be used to check if b is a member of a given class. Note that it is not a member of class B, but it is a member of class A.

06:11 Now that you know the steps that Python takes internally to create instances of a given class, you’re ready to dig a little deeper into other characteristics of the .__init__() and .__new__() special methods and the steps that they run. So in the next section, you’ll start that off by looking at .__init__().

Avatar image for Andras

Andras on Jan. 1, 2025

Great video, thank you! Just a minor comment: at 3:50 you call __init__ on the point instance object to initialize it, which is fine. But you could have also called it on the class like Point.__init__(point, 21, 42). Maybe you could point it out that once we have the instance object both approach does the same. However, regarding __new__, we can only call it on the class as that will create the first (empty) instance of the class.

Avatar image for kishore.99v

kishore.99v on Aug. 12, 2025

When trying to create an instance of b = B(21), if the instantiation process is not happening for Class B, then when and how it will be completed and make use of it in the further code?

If b is not instance, is not created and all attributes are not initialized then what is the point to have __new__ method inside Class B, what are the situations we can use __new__ method ? its just to check/see the instance creation process?

Avatar image for Bartosz Zaczyński

Bartosz Zaczyński RP Team on Aug. 12, 2025

@kishore.99v This was an illustrative example, and you wouldn’t write code like that in a real-world scenario. When you instantiate a class, Python invokes its .__new__() method first, and then calls .__init__() on the returned instance. However, if the .__new__() method returns a completely different object, then the original .__init__() method won’t run. You can find more details about this mechanism in the associated tutorial: Python Class Constructors: Control Your Object Instantiation.

Avatar image for kishore.99v

kishore.99v on Aug. 13, 2025

@Bartosz for the explanation, one question on the return statement. Point is not a child class. Why and can we use super() keyword like this?

class Point:
    def __new__(cls, *args, **kwargs):
        print("1. Create a new instance of Point.")
        return super().__new__(cls)
Avatar image for Bartosz Zaczyński

Bartosz Zaczyński RP Team on Aug. 13, 2025

@kishore.99v Although the Point class in your example doesn’t explicitly extend any base classes, it inherits from Python’s object type implicitly. In this case, calling super() delegates to object, which you can verify by looking at the method resolution order (mro):

>>> class Point:
...     def __new__(cls, *args, **kwargs):
...         print("1. Create a new instance of Point.")
...         return super().__new__(cls)
...
>>> Point.__mro__
(<class '__main__.Point'>, <class 'object'>)

object is the next parent class in the inheritance chain of your class.

Become a Member to join the conversation.