When reading over other people’s Python code, many beginners are puzzled by the
__init__(self) method. What’s its purpose? This article answers this question once and for all.
So what’s the purpose of
__init__(self) in Python?
The __init__ method is the constructor of a class. The constructor method initializes the attributes of a classes’ instance. Say, you define a class Dog with instance attribute color. When creating a specific Dog instance, the constructor method is where you set its color.
While this answers the question, if you’ve got any ambition in becoming a professional Python coder, it’s not enough to know that the
__init__ method is the constructor of a class. You also need to know how to use the constructor in your own projects—and how to customize its arguments. A thorough understanding of the constructor serves as a strong foundation for more advanced concepts in object-oriented Python programming. Read on to learn the other half of the equation.
How to Use the __init__ Method in Practice? A Simple Example
We’ll use some terms of object-oriented programming in Python to explain our example. Make sure to study the following cheat sheet (you can also download the PDF here). Click the image to get the cheat sheet (opens in a new tab). If you’re already comfortable with basic object-orientation terminologies like classes and instances, simply read on.
You’ve learned that the
__init__ method is the constructor method of a class. You call the constructor method to create new instances (or objects). But how exactly does this play out in practice? Before we dive into the correct use, we need to understand the arguments (or parameters) of the constructor method.
The Self Argument
__init__ constructor requires at least one argument. According to the PEP8 standard, it’s good practice to denote this argument as
self. In any case, the
self argument points to the newly-created instance itself and it allows you to manipulate the instance attributes of the new instance. In the dog example, you’d use
self.color = "blue" to set the newly-created dog’s
color attribute to the string
Let’s have a look at the following basic code example:
class Dog: def __init__(self): self.color = "blue" bello = Dog() print(bello.color) # blue
- We create a new class Dog with the constructor
- We create a new instance of the class
bello. There are two interesting observations: First, we use the class name rather than the constructor name to create the new instance. Python internally calls the __init__ method for us. Second, we don’t pass any argument when calling
Dog(). Again, Python implicitly passes a reference to the newly created instance (
bello) to the constructor
- We print the color attribute of the newly-created
belloinstance. The result is the string value
"blue"as defined in the constructor.
However, this minimal example is unrealistic. Some dogs are brown, others are black, and only some are blue.
Multiple Constructor Arguments
So how can we create different dogs with different colors? We can easily achieve this by using more arguments, in addition to
self, when defining our constructor
__init__. Here’s another example where we create two dogs with different colors. Can you spot their colors?
class Dog: def __init__(self, color): self.color = color bello = Dog("blue") print(bello.color) # blue alice = Dog("brown") print(alice.color) # brown
In contrast to the first example, we now define the constructor
__init__(self, color) with two arguments rather than one.
The first is the
self argument as before. The second is a custom argument
color that is passed through by the caller of the constructor. In our case, we create two Dog instances,
alice, by specifying the
color argument for both.
Note that the
self argument is handled implicitly by the Python programming environment: Python simply passes a reference to the respective
Dog instance to the
What’s the Difference between the Constructor and the Initializer?
Well, I haven’t used a very accurate terminology in the previous paragraphs. I used the term “constructor” for both the call
Dog() and the call
__init__(). But only the former call can be denoted as constructor method because only this call actually creates a new instance. At the time, we call the method
__init__, the instance has already been created (Python passes it to us via the
self argument). That’s why a more precise term for the
__init__ method is initializer method. That’s how I’ll denote it in the following to make up for it. 😉
What’s the Meaning of the Underscores in the __init__ Method Name?
I’ve written a whole article about the meaning of the underscore in Python. Check it out if this topic interests you further. The key takeaway, however, is the following:
The double underscore “__” (called “dunder“) is used to make an instance attribute or method private (cannot be accessed from outside the class) — when used as leading dunder. When used as enclosing dunder (e.g. “__init__”) it indicates that it is a special method in Python (called “magic method”).
How to Use __init__ in an Inherited Class?
An inherited class is a class that inherits all attributes and methods from a parent class. Here’s an example:
class Dog: def __init__(self, color): self.color = color class CuteDog(Dog): def __init__(self, color): Dog.__init__(self, color) self.hairs = True bello = CuteDog('brown') print(bello.hairs) # True print(bello.color) # brown
Inheritance is very important in Python. In the example, the parent class is the class Dog you already know from above. The initializer method __init__ defines the color of this dog.
Now, we also create a new class
CuteDog that inherits all attributes from the parent class
Dog. You can define inheritance by specifying the name of the parent class within the brackets after the child class:
The interesting thing is that the __init__ method of the child class CuteDog calls the __init__ method of the parent class. This makes sense because the child class has the same attributes as the parent class—and they need to be initialized, too.
The more Pythonic way, however, is to use the
super() function that makes it easier for you to access the parent class:
class Dog: def __init__(self, color): self.color = color class CuteDog(Dog): def __init__(self, color): super().__init__(color) self.hairs = True bello = CuteDog('brown') print(bello.hairs) # True print(bello.color) # brown
With the help of the super() function, you can easily reuse the initializer method of the parent class.
Let’s have a look at a few related questions.
Is __ init __ Necessary in Python?
No. You can simply skip the initializer method. As a result, your class won’t have any instance attributes directly after its creation. However, you can add instance attributes dynamically at any future point in time. Here’s an example:
class Dog: None bello = Dog() bello.color = "blue" print(bello.color) # blue
How beautiful! You can even create empty classes and “fill in” the methods and attributes later in Python.
What Does __ init __ Return?
__init__ method itself returns nothing. Technically, Python first uses the constructor method
Dog() before it uses
__init__ to initialize all attributes. Hence, only the constructor returns the newly-created instance.
Can __init__ Return a Value?
No. The only return value that doesn’t cause a runtime error is
None. All other return values cause an error. See the following code example:
class Dog: def __init__(self, color): self.color = color return 0 bello = Dog("blue") # TypeError: __init__() should return None, not 'int'
So never use any return value in the __init__ method and you’re good to go.
Where to Go from Here?
Thanks for reading through the whole article. You’ve learned that the
__init__ name is reserved for the Python initializer method that is called within the constructor.
The article requires a thorough understanding of the Python basics. Investing time to learn and study those is vital for your success as a professional coder.
To help people grow their skills in an automated, personalized way, I’ve created a free Python email course “Coffee Break Python” that grows your skill level in a seemingless way. Day after day after day…