Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Initializing Objects With .__init__()

00:00 Object Initialization With .__init__(). In Python, the .__init__() method is probably the most common special method you’ll override in your custom classes.

00:11 Almost all your classes will need a custom implementation of .__init__() to allow you to initialize your objects properly. The purpose of this initialization step is to leave your new objects in a valid state so that you can start using them right away in your code. In this section, you’ll learn the basics of writing your own .__init__() methods and how they can help you customize your classes.

00:34 The most bare-bones implementation of .__init__() that you can write will just take care of assigning input arguments to matching instance attributes.

00:43 For example, let’s say you’re writing a Rectangle class that requires .width and .height attributes. In that case, you’d create codes similar to what’s seen on-screen.

00:57 As you’ve already learned, .__init__() runs the second step of the object instantiation process in Python. Its first argument, self, holds the new instance that results from calling .__new__().

01:08 The rest of the arguments to .__init__() are normally used to initialize instance attributes. Here, you initialize the rectangle’s .width and .height attributes using the width and height arguments to .__init__().

01:21 It’s important to note that, without counting self, the arguments to .__init__() are the same ones that you passed in the call to the class constructor. So, in a way, the .__init__() signature defines the signature of the class constructor.

01:36 Additionally, keep in mind that .__init__() must not explicitly return anything other than None, or you’ll get a TypeError exception.

01:45 Here, the .__init__() method attempts to return an integer, which ends up raising a TypeError exception at runtime.

01:55 The error message in this example says that .__init__() should return None. However, you don’t need to return None explicitly, because methods and functions without an explicit return statement return None implicitly in Python.

02:10 With this implementation of .__init__(), you ensure that .width and .height get initialized to a valid state when you call the class constructor with appropriate arguments.

02:19 That way, your rectangles will be ready for use right after the construction process finishes. In .__init__(), you can also run any transformation over the input arguments to properly initialize the instant attributes. For example, if your users will use Rectangle directly, then you might want to validate the supplied width and height and make sure that they’re correct before initializing the corresponding attributes.

02:51 In this updated implementation of .__init__(), you make sure that the input width and height arguments are positive numbers before initializing the corresponding .width and .height attributes.

03:15 If either validation fails, then you raise a ValueError, as seen on-screen.

03:27 A more Pythonic technique to tackle attribute validation is to turn attributes into properties. To learn more about properties, check out this Real Python course.

03:39 Now let’s say that you are using inheritance to create a custom class hierarchy and reuse some functionality in your code. If your subclasses provide an .__init__() method, then this method must explicitly call the base class’s .__init__() method with appropriate arguments to ensure the correct initialization of instances. To do this, you should use the built-in super() function, as on-screen.

04:23 The first line in Employee’s .__init__() method calls super().__init__() with a name and birth_date as arguments.

04:29 This call ensures the initialization of name and birth_date in the parent class, Person. This technique allows you to extend the base class with new attributes and functionality. Here, the .position attribute is used only by the Employee class and is part of the Employee() initialization function.

04:55 This is confirmed by viewing the attributes of the john object, as seen on-screen.

05:09 You should know that the base implementation of .__init__() comes from the built-in object class. This implementation is automatically called when you don’t provide an .__init__() method in your classes.

05:22 You can make your objects’ initialization step flexible and versatile by tweaking the .__init__() special method. To this end, one of the most popular techniques is to use optional arguments.

05:33 This technique allows you to write classes in which the constructor accepts different sets of input arguments at instantiation time. Which arguments to use at a given time will depend on your specific needs and context. As a quick example, check out the following Greeter class.

05:58 Here, .__init__() takes a regular argument called name. It also takes an optional argument called formal, which defaults to False. Because formal has a default value, you can construct objects relying on this value or by providing your own.

06:13 The class’s final behavior will depend on the value of formal. If this argument is false, then you’ll get informal greeting when you call .greet(). Otherwise, you’ll get a more formal greeting.

06:30 To try the Greeter class out, save the code into a file called then open a Python session in the working directory and run the following code.

06:45 Here, you create an informal_greeter object by passing a value to the name argument and on the default value of formal.

06:53 You get an informal greeting on your screen when you call .greet() on the informal_greeter object. In this example, you use a name and a formal argument to instantiate Greeter. Because formal is True, the result of calling .greet() is a formal greeting. Even though this is a toy example, it showcases how default argument values are a powerful Python feature that you can use to write flexible initializers for your classes.

07:21 These initializers will allow you to instantiate your classes using different sets of arguments depending on your needs. Now that you know the basics of the .__init__() special method and the object initialization step, it’s time to change gears and start diving deeper into .__new__() and the object creation step.

Avatar image for Khaled

Khaled on Dec. 6, 2023

Do you happen to know how I can initialize a class using an if-block that selects between 3 @classmethod type of methods based on the parameters passed into the init() ?

Become a Member to join the conversation.