For more information on properties, you can check out Python’s property(): Add Managed Attributes to Your Classes.
Exploring the Instantiation Process
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__()
.
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?

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.
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)

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.
Andras on Jan. 1, 2025
Great video, thank you! Just a minor comment: at 3:50 you call
__init__
on thepoint
instance object to initialize it, which is fine. But you could have also called it on the class likePoint.__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.