For more information on properties, you can check out Python’s property(): Add Managed Attributes to Your Classes.
Exploring the Instantiation Process
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
.__init__() special methods, for demonstration purposes.
This line defines the
Point class using the
class keyword followed by the class name.
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.
The method also takes
**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.
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.
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.
This method takes a first argument called
self, which holds a reference to the current instance. The method also takes two additional arguments,
These arguments hold initial values for the instance attributes
.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
.y attributes, respectively. To do this, they use the provided input arguments
y. Finally, these lines implement the
.__repr__() special method, which provides a proper string representation for the
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.
Point() class constructor creates, initializes, and returns a new instance of the class. This instance is then assigned to the variable
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.
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.
This can be demonstrated by trying to access the
.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.
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.
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.
Next, you’ll see an example of this on-screen, where the
.__new__() method of the
B class returns an instance of the
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.
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.
b doesn’t have a
.b_value attribute. In contrast,
b does have an
.a_value attribute with a value of
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
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
.__new__() special methods and the steps that they run. So in the next section, you’ll start that off by looking at
Become a Member to join the conversation.