Hint: You can adjust the default video playback speed in your account settings.
Hint: You can set the default subtitles language in your account settings.
Sorry! Looks like there’s an issue with video playback 🙁 This might be due to a temporary outage or because of a configuration issue with your browser. Please see our video player troubleshooting guide to resolve the issue.

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

Become a Member to join the conversation.