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 greet.py
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.
Become a Member to join the conversation.
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() ?