How to Provide Multiple Constructors in Python?

How to Provide Multiple Constructors in Python?
Python does not support constructor overloading. If you try to overload the constructor, the last implementation will be executed each time. Any previous implementation will be over-written by the latest one. Example Consider the following example. In class Person two __init__() functions are provided, however the implementation of the first __init__() function is over-written by the later implementation.
Output
To provide multiple constructors in Python, several techniques are being used to construct classes that alter their behavior. This can be done using a simple simulation based on input arguments or data types of arguments. A cleaner way is also explained later in the article. Multiple constructors in Python can be provided by transforming some methods into class methods using @classmethod or providing multiple implementations to the default constructor __init__() using the @singledispatchmethod function.
Note that these methods have advantages and drawbacks that should be considered when choosing a method to implement multiple constructors in Python.
What is Instantiating Classes in Python?
Object Oriented Programming is supported in Python via classes and objects. A class is a user-defined data type that acts like a blueprint. It consists of data members and functions to manipulate the data. Classes are useful for creating multiple objects of the same data type. When these objects are created by the user, this is termed instantiating a class. The object created is also known as an instance of the class.
Python uses special methods when instantiating a class. Python uses the __init__() method to initialize the data members of the object. When instantiating a class, the values of all the data members of the class need to be passed as arguments. Another special method __str__() is used to return the string representation of the object. This function is called when the object of the class is printed.
Example A class Student is defined below that has two data members: name and age. The class is instantiated in the main function.
Output
Instantiating a class in Python is a two-step process:
- In the first step, the __new__() method is called. This special method is called object creator in Python. This function returns a new instance of the class. In the above example, we have not provided the definition and are using the default implementation of this method, which is provided by Python's Object class.
- In the second step, the object created is passed to the __init__() method to initialize the data members of the class. This function is called the instance initializer method in Python.
Defining Python Multiple Class Constructors
There are multiple ways to provide multiple constructors in Python. Suppose you want to have a function in Python, that behaves differently depending on if you send in a list or a string or any other type as a function argument. In statically typed languages like C++ and Java, we explicitly specify the type of the data in the function signature. This enables us to overload that function in statically typed languages and is termed function overloading.
Python doesn't support function overloading. The classes in Python maintain a dictionary __dict__, which holds the class namespace. This class namespace is simply a dictionary mapping the attributes and methods of the class to function implementation in memory. Now dictionaries cannot have repeated keys so Python does not have function overloading. Example Consider the example below. A class Person is defined with two data members and two functions.
Output
From the output, we can see that the function names and other attributes are mapped to memory addresses.
Multiple constructors in Python can be simulated using various strategies. Two of the most used strategies are provided in the upcoming sections. Later, we will discuss a more refined and elegant way to define multiple constructors in Python using the @classmethod and @singledispatchmethod functions.
Simulation of Multiple Class Constructors in Your Classes.
As a software developer, sometimes you need to find creative solutions to the problem given to you. Now, Python does not support constructor overloading, but that doesn't mean that the same behavior cannot be achieved using some strategy. In this section, we will look at two such strategies to define multiple constructors in Python:
- Using default values and optional arguments in __init__() method.
- Checking data type of arguments passed in the __init__() method.
Both of these methods require only one constructor and implementation of the __init__() method.
Using Default Values and Optional Arguments in __init__() Method.
A common way to simulate multiple fields in the __init__() function is using optional arguments. It is like providing a list or a dictionary as an argument using variable length arguments *args. Now depending on the size of the list, we can determine the operations to be performed.
Example Consider a class Series that defines two data members: firstTerm and difference. Now, we can use 0 as the default value for these numbers. We can simulate multiple constructors depending on the number of input arguments.
In the above implementation, if the value of difference or firstTerm is not provided then it is initialized to 0. Overall, we are simulating three constructors in the above example.
This is a fairly popular method to provide multiple constructors in classes in Python.
Checking Data Type of Arguments Passed in __init__() Method.
This is another way to provide multiple constructors in Python. We can use the data type of the arguments to determine the behavior of the constructor. Python provides an inbuilt function isinstance() to check the type of the variable. The function returns True if the object is an instance of provided class. Example
Output
Now, suppose we define a class Date that defines three data members: day, month, and year representing a date in the calendar. Now the input can be given in many different formats like string, list, etc. We can use this approach to provide multiple constructors in Python. Example
Output
In this way, we can use the type of data arguments to provide multiple constructors. This method, however, has some drawbacks as it doesn't scale. If a class can take inputs with multiple data types then the implementation will become tedious and long. Moreover, this method is not extensible.
Methods of Providing Multiple Class Constructors
The __init__() is a special built-in method in Python. We can simulate multiple __init__() functions using the above workaround. In addition to the methods described above, Python3 also provides two decorators @classmethod and @singledispatchmethod to simulate multiple constructors in Python. Decorators are special messages written above the function or a class to convey information to the compiler or the Python interpreter. Decorators allow a programmer to extend the behavior of the method without modifying it.
Providing Multiple Constructors with @classMethod Decorator
This technique can be used to provide multiple constructors in Python. The decorator @classmethod is used to convert any method into a class method. A class method takes the class itself as an argument. It is passed implicitly when the class method is called.
Example In the example below, a class Person is defined. This class has a class method classMethod that accepts the class as a parameter cls.
Output
A class method can be invoked using a class name or using the instance of the class. The class method of class Person is invoked using the statement Person.classMethod(). Since a class method does not require an instance of the objects and can be invoked using the class name, we can use this method to provide multiple constructors in Python. In this technique, we will handle both the processes: object creation and initialization.
Let us consider a class Triangle that has three data members: a, b, and c, representing the sides of the triangle. Now we want to provide constructors such that the objects can be created when the input is provided as:
- Set of three integers (a, b, c)
- As a list [a, b, c]
- As a string "a b c"
Now to provide multiple constructors in Python, we can use the __init__() method for the first requirement where the integers are given explicitly. To provide the constructor when the list or string input is given, we will use a class method fromList and fromString respectively. These methods return an object of the class. In these methods, we first extract the sides of the triangle as integers and then return a new object.
Example
Output
In this way, we can provide multiple constructors in Python to the class Triangle.
In this method, we need to explicitly call the specific method as per the input, in the main function. When the class method is called, we can extract the arguments from the input in the form needed by the __init__() function. We then return a new instance using the argument list specified in the __init__() function of the class. We are using these class methods like an object factory for creating new instances but with custom input parameters.
Providing multiple constructors with @singledispatchmethod
In this method, we use a utility from the functools module in Python3. Starting from Python3.8, we can use the decorator @singledispatchmethod to convert a method into a single-dispatch generic function. We use this decorator to provide multiple constructors in Python. A single-dispatch generic function is a collection of multiple functions that have the same name, and implement the same operations but for different data types. A dispatch algorithm provided by Python is used to determine which implementation to run based on the type of the single argument.
Let us understand this using an example. Suppose we have a class Name that declares two variables firstName and lastName.
The requirement states that the object of this class can be declared when:
- Input is provided in form of a string.
- Input is provided in form of a list.
Now to create an object, we need to provide multiple constructors. To do this we will use the @singledispatchmethod decorator.
- First, we need a base implementation for the __init__() function and decorate it with the @singledispatchmethod decorator.
- Next, we need to provide an alternative implementation based on the type and register each method using the decorator <function name>.register(<data type>).
Output
With this technique, we can add multiple constructors in Python, and run them according to the type of the first argument.
In the above example, we can create objects of the class Name with the string argument and the list argument. Now suppose, if there is a type that is not defined, then the default implementation of the __init__() function will be executed. So when we try to create an object with an int argument, we get the error.
Exploring Multiple Constructors Within the Existing Classes.
In this section, we will explore how multiple constructors are implemented in Python libraries using the @classmethod decorator.
Constructing Dictionaries Using .fromkeys() Method
Python provides dictionaries as a fundamental data type. Dictionaries are one of the most used data structures in Python. There are many ways to define instances of a dictionary. We can define a dictionary:
- Using key-value pairs {key: value}.
- Using the keyword dict().
- Using the alternative constructor fromkeys().
Suppose we want to initialize a dictionary with multiple keys with a default value, then, in this case, we can make use of the constructor fromkeys() provided by Python. It takes an iterable and a value as arguments and creates a dictionary using the keys in the iterable with the value provided. In a large application, this reduces the effort of coding and makes use of the inbuilt function.
Example
Output
The alternative constructor fromkeys() is provided by Python and is implemented using the decorator @classmethod. It is also present in the classes OrderedDict, DefaultDict and UserDict.
Creating datetime.date Objects
Multiple constructors are also available in the datetime.date class in Python's standard library. This class defines the date using the data members: year, month, and day. It also provides constructors to convert dates from ordinal and timestamps to this format. Some of the constructors provided by this class are fromordinal(), fromtimestamp(), fromisoformat(). All these constructors are used to initialize an object of datetime.date when the input is given in different formats. Example
Output
Learn more
Conclusion
- Python does not support functional or constructor overloading.
- Multiple constructors in Python can be simulated by providing optional arguments and using default values.
- Multiple constructors in Python can also be simulated based on the data type of the argument passed in the __init__() function. However, this method might not scale.
- Multiple constructors can be provided by defining class methods to handle different types of input arguments. Class methods can be defined using the @classmethod decorator
- Starting from Python3.8, multiple constructors can be provided by providing multiple implementations to the __init__() method and using an inbuilt dispatch algorithm to execute operations depending on the data type of the first argument.