Article Agenda
This post is dedicated towards understanding how we can create alternative constructors in Python. Also, we would be taking a look at a real developmental scenario where I felt comfortable using it. To cut this short, we would be covering:
Introduction
Python OOPs has rocked the world with its simple yet stunning flow of programming. Almost all the programs and software written in Python follow the OOPs paradigm. The OOP in Python is so modernized and enhanced that huge amount of developers are making a shift towards this amazing Programming language.
In case you are wondering what an OOP is, I already have a Python OOP post on this, which gives you a brief overview about it. You may want to give it a thorough read.
Constructors
Constructors by definition, is a subroutine designed to create an object in a particular class. In layman's terms, a method, which gets automatically called at the time of object creation and assists it.
Constructors are like ordinary methods defined inside the class. The only difference being, we need not call it explicitly. Programming languages automatically calls it while creating the object of the class.
In C++, constructors have the same name as the class name. For example (I know this is a Python tutorial, but I really felt the urge to show you the difference. So, here you go):
class MyClass // Class name
{
public:
int a, b;
// Constructor. Notice how its name is same as class name
MyClass()
{
// I will be automatically executed during instantiation
}
};
int main()
{
MyClass obj; // instantiation.
}
In Python, this is not the case. However, there is a huge misconception out there:
The __init__()
vs __new__()
. Which one is the real constructor?
As opposed to a popular yet wrong belief where __init__()
method is considered to be constructor, its actually the __new__()
method which is the constructor of the class. To put it more clearly:
-
__new__()
: This method is called automatically to control the object creation. -
__init__()
: This method is also called automatically during object creation, but this is more of an initializer method which initializes the object attributes. That's why we used it in our OOPs concept (an earlier post), to initialize our object attributes.
Moreover, if both __new__()
and __init__()
methods exist in the same class, then __new__()
is called first and then Python interpreter decides whether to call __init__()
or not.
So, from the OOP standpoint, and from the above observations, it can be safely concluded that __new__()
is the real constructor. But several Devs just want to stay out of this pandemonium. Therefore, instead of going after this "init vs new thing", they adopted another way to create constructors, enter the Alternative Constructors
Alternative Constructors
Alternative constructors are actually class methods which serves the purpose of object creation. We hack the class methods and command them to control the object creation. This is pretty similar to a constructor's (__new__()
's) working.
There is a convention for naming methods to be used as alternative constructors. All such methods should start with from_
. For example, if I have a method say, getDetails()
and if I were to make it an alternative constructor, then I would have to rename it as from_getDetails()
. Although this is not necessary, but it is considered to be a good practice.
The following snippet shows the basic syntax of defining alternative constructors (AC):
class MyClass:
@classmethod
def from_alternativeConstructor(cls): # Alternative Constructor
return cls() # returns object
object = MyClass.from_alternativeConstructor() # calling AC
# an object is crafted successfully due to the execution of AC
A Real Application Example
While I was developing a backend, I had a long list of strings. I had to come up with a way to convert these strings to objects. Luckily, I had AC by my side and the task went on smoothly. In real world, you would get raw data like these. You would have to circumvent these obstacles and find a solution.
The following snippet shows a demonstration of how I converted a long list of strings (but here, for the sake of simplicity, lets take a single string) and then converted it into objects.
class Professor:
def __init__(self,name,id,age):
self.name = name
self.id = id
self.age = age
@classmethod
def from_getDetails(cls, string): # Alternative Constructor
name, id, age = string.split(',') # split string and assign to variables
return cls(name,id,age) # returns object
details = "Jack Robins,2233394,45"
prof = Professor.from_getDetails(details)
print(prof.name,prof.id,prof.age) # prints --> "Jack Robins" 2233394 45
The string is now converted to an object and I can easily access it using its attributes. So, this was all about alternative constructors. One of the most interesting ways to bypass the basic working system of OOPs and also, exploiting the most out of it. After all, we are programmers, its in our DNA to exploit stuff and get things working for us.
Would You Like to Support Me?
If you want to support me and my contents, then go ahead and consider doing it. I would highly appreciate that:
- YouTube Channel: Home to all sorts of peculiar tutos.
- GitHub: Looking forward to your PR 😉
Top comments (2)
While I think it important indeed to understand the difference between
__new__()
and__init()__
I detect a degree of unnecessary hubris or smugness in any claim that one is the real constructor. They are simply differentiated by the fact that__new__
receives as its first argument the class object, and the__init__
receives as it's first argument the instantiated object. and that__new__
is tasked with returning an instance ... most other languages lack a clear analog because classes are not themselves objects as they are in Python (where basically everything is - an object that is). Nether is more real than the other.It's true however that for the vast majority of use cases I have encountered, and by projection I suspect most people encounter, for constructors is do whatever is needed during instantiation of an object , without holding the undesired responsibility of actually creating and returning an instance). This is in fact, if we are to be pedantic,closer to what a C++ constructor is used for, than the responsibility
__new__
carries with it, that is C++ constructors are also called with no instance creation responsibility, much rather in the context of an existing instance already (while it's not passed as an argument, it runs within in the scope of one).All that said, your perfectly right, because Python does not support overloading of functions with different signatures, the traditional means of providing different construction paths is through differently named class methods that return an an instance (as
__new__
is obliged to do).Great addition to the
__init__()
vs__new__()
topic. My views were based on the practical understanding and I was being pretty restrictive when I said__new__()
was the real constructor. I made this claim observing the fact that whenever you instantiate, in the backend, Python calls in__new__()
first. Then, its the__new__()
which "privately" calls__init__()
.Yes, I strongly agree that both are called in while creating an object. The reason I was being defensive with
__new__
is due to the strict definition of constructor I mentioned in the post and the fact that class makes an implicit call to__new__()
while instantiating the object.Again, this is purely debatable. It depends on the degree of freedom you add into the definition of constructor and purpose for which one had been using constructors for.