DEV Community

Cover image for Alternative Constructors in Python
P0intMaN
P0intMaN

Posted on

Alternative Constructors in Python

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
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.

}
Enter fullscreen mode Exit fullscreen mode

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

ac
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
Enter fullscreen mode Exit fullscreen mode

A Real Application Example

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
Enter fullscreen mode Exit fullscreen mode

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:

Top comments (2)

Collapse
 
thumbone profile image
Bernd Wechner

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).

Collapse
 
p0intman profile image
P0intMaN

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.