You may have encountered the methods in Python that are prefixed and suffixed with double underscores, those methods are called “Dunder Methods”. These methods are also called “magic methods”.
Dunder methods are used to overload specific methods in order to make their behavior unique to that class.
Python has a rich collection of built-in dunder methods and a few are listed below:
- __init__
- __call__
- __repr__
- __str__
- __len__
- and more…
In this article, we will look at two dunder methods(__init__
and __call__
) that are commonly used in Python classes. How do they differ, and when do we need to use them within the Python program?
__init__ Method
The __init__
method is used to initialize the object’s attributes after the object of the class is created.
1 2 3 4 5 6 7 8 9 10 |
class Language: def __init__(self, lang, year): self.lang = lang self.year = year def data(self): print(f"{self.lang} was released in {self.year}") object = Language("Python", "1991") object.data() |
The __init__
for the class Language
is created in the preceding code, and it takes the parameters lang
and year
.
Then we created the instance of the class Language
, passed it the necessary arguments, and called the method data
on the instance object
.
1 |
Python was released in 1991 |
The arguments "Python"
and "1991"
passed to the class are actually stored in the parameters lang
and year
passed to the __init__
method, which initializes the instance variables (self.lang
and self.year
) with these values.
Every time we create an object, the __init__
method is automatically invoked. We’ll get different results if we create another object and pass different values.
1 2 3 4 5 |
object1 = Language("JavaScript", "1995") object1.data() ---------- JavaScript was released in 1995 |
Syntax
Thus, we can conclude that the syntax of the __init__
method can be written as the following.
1 2 3 |
class SomeClass: def __init__(self, arg1, arg2, ...) # constructor body |
Here,
self
– is an instance of the class. Mandatory.
arg1
and arg2
– are the parameters. We can pass as many parameters as we want or the field can also be left empty.
What if we pass more than the number of parameters that a class takes?
1 2 3 4 5 |
class Language: def __init__(self, lang): self.lang = lang object1 = Language("JavaScript", "1995") |
The above code will throw an error and prompts the following message.
1 2 3 4 |
Traceback (most recent call last): ... object1 = Language("JavaScript", "1995") TypeError: __init__() takes 2 positional arguments but 3 were given |
The message states that two arguments were allowed, but three were passed. But we passed two arguments, not three then why did this happen?
This occurred because __init__
only accepts self
and lang
. When we instantiated the class with arguments, the keyword self
, which represents the object’s instance, was passed along with the arguments automatically.
So, when we passed the arguments "JavaScript"
and "1995"
, the self
was automatically passed, making three arguments passed to the class Language
.
__init__ with and without parameters
Python constructor(__init__
) can be created with or without passing any parameters.
Default __init__ constructor
A constructor created without parameters other than self
(a reference to the instance being constructed) is called the default constructor.
1 2 3 4 5 6 7 8 |
class Language: def __init__(self): self.lang = "C++" self.year = 1985 object1 = Language() print(object1.lang) print(object1.year) |
We created self.lang
and self.year
and assigned the default values "C++"
and "1985"
respectively. We accessed the lang
and year
by using the instance of the class object1
.
1 2 |
C++ 1985 |
We can also override the attribute’s default value by assigning a new value before accessing the attribute from the class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class Language: def __init__(self): self.lang = "C++" self.year = 1985 object1 = Language() # Assigned new value to the lang object1.lang = "Python" print(object1.lang) print(object1.year) ---------- Python 1985 |
__init__ with parameters
We’ve already seen some examples where we used parameters to create the constructor. Pass the parameters to the constructor, as shown in the following example. Then we created an object or instance of the Vehicle
class and passed the arguments to it. The output was then obtained by calling the vehicle
function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class Vehicle: def __init__(self, name, model): self.name = name self.model = model def vehicle(self): print(f"Brand: {self.name} and Model: {self.model}") bmw_car = Vehicle("BMW", "X5") audi_car = Vehicle("Audi", "A4") bmw_car.vehicle() audi_car.vehicle() ---------- Brand: BMW and Model: X5 Brand: Audi and Model: A4 |
__call__ method
When we invoke a function, we simply use the function name with parenthesis, such as hello()
, to notify the interpreter that a function is being called. Well, we can say that it is a shorthand for hello.__call__()
.
When we invoke a function in Python, the interpreter executes the __call__
method in the background.
1 2 3 4 5 6 7 8 9 |
def func(a, b): print(a + b) func(32, 8) func.__call__(8, 9) ---------- 40 17 |
In the above code, first, we called the function func
simply as we usually do and then by using the __call__
.
__call__ inside Python classes
The concept behind using __call__
is to call the instances of the classes as if they were a function. Instances of classes can be made callable by defining a __call__
method in their class.
1 2 3 4 5 6 7 8 9 |
class Demo: def __init__(self): print("Hello from constructor.") def __call__(self): print("Hello from call.") example = Demo() example() |
In this case, we called the class object example
as if it were a function.
1 2 |
Hello from constructor. Hello from call. |
Syntax
The syntax of the __call__
method is
object.__call__(self, *args, **kwargs)
Here,
self
– reference of the object.
args
and kwargs
– arguments and keyword arguments.
__call__ with parameters
1 2 3 4 5 6 7 8 9 10 11 |
class Student: def __init__(self, id, name): self.id = id self.name = name def __call__(self, school): print(f"The id of {self.name} is {self.id}.") print(f"The school name is {school}.") detail = Student(45, "Sachin") detail("GSS") |
We passed the parameter school
to the __call__
method just like we do when we create the constructor. This will allow us to pass the argument within the object of the class as we did in the above code.
1 2 |
The id of Sachin is 45. The school name is GSS. |
__call__ with decorators
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class Demo: def __init__(self, action): self.action = action print("Hello from constructor.") def __call__(self): self.action() print("Hello from call.") @Demo def decor(): print("Called using decorator.") decor() |
We first generated the decorator(@Demo
) for the class Demo
, followed by the function decor
. Then we invoked the decor
function and got the result shown below.
1 2 3 |
Hello from constructor. Called using decorator. Hello from call. |
The decorator altered the behaviour of our class Demo
, and we accessed the class’s attributes simply by invoking the decor
function.
If we examine more closely, the function decor
was supplied as an argument to the class Demo
, the decor’s return value was saved within the action
variable, and the class was called and produced the output.
The decorator part in the above code is equivalent to the following.
1 2 3 4 |
def decor(): print("Called using decorator.") decor = Demo(decor) |
Conclusion
The __init__
method is also called the constructor method which is used to initialize the objects of the specific class whereas the __call__
method allows us to call the object of the class like a function.
The __init__
method created without passing parameters is called the default __init__
constructor.
When we call a function using ()
, in actuality, the __call__
method is implemented in the function.
We’ve coded many examples to get a better understanding of both methods.
🏆Other articles you might be interested in if you liked this one
✅Introduction to the different types of class inheritance in Python.
✅Build a deep learning model using the transfer learning technique.
✅Tackle the shortage of data by using the data augmentation technique.
✅Upload and display images on the frontend using Flask in Python.
✅Integrate TailwindCSS into the Flask app.
✅Avoid conflicts between dependencies by using virtual environments.
That’s all for now
Keep Coding✌✌