Python Constructors & Function Overloading

Previous Python Constructors & Function Overloading Next

Python Constructors & Function Overloading Interview Questions

What are constructors in Python and what is the __init__ method?
Constructors are special methods called when an object is created. __init__ is Python's constructor that initializes object attributes. It's NOT a true constructor - Python has __new__ for object creation and __init__ for initialization.
class Person:
    def __init__(self, name, age): # Constructor
        self.name = name
        self.age = age

p1 = Person("Alice", 30) # __init__ is called automatically
What is the difference between __init__ and __new__ in Python?
__new__:
Creates and returns a new instance (actual constructor). Called before __init__. Returns an instance.
__init__:
Initializes the created instance. Called after __new__. Returns None.
class MyClass:
    def __new__(cls, *args, **kwargs):
        print("Creating instance")
        return super().__new__(cls)

    def __init__(self, value):
        print("Initializing instance")
        self.value = value

obj = MyClass(10)
# Output: "Creating instance" then "Initializing instance"
Does Python support constructor overloading like Java/C++?
No, Python does NOT support traditional constructor overloading. You cannot have multiple __init__ methods with different parameters. Python achieves similar functionality using:
  • Default arguments
  • Variable-length arguments (*args, **kwargs)
  • Class methods as alternative constructors
# Python's approach instead of overloading
class Person:
    def __init__(self, name=None, age=None): # Default args
        self.name = name
        self.age = age

    @classmethod
    def from_dict(cls, data): # Alternative constructor
        return cls(data.get('name'), data.get('age'))
What are default constructors and parameterized constructors in Python?
Default Constructor:
__init__ without parameters (except self).
Parameterized Constructor:
__init__ with parameters.
# Default constructor
class DefaultExample:
    def __init__(self): # Default
        self.value = 0

# Parameterized constructor
class ParamExample:
    def __init__(self, name, age): # Parameterized
        self.name = name
        self.age = age
What is function/method overloading in Python? Does Python support it?
Function overloading allows multiple functions with same name but different parameters. Python does NOT support traditional compile-time overloading. The latest defined function overwrites previous ones.
Warning: This code won't work as expected in Python!
def add(a, b): return a + b
def add(a, b, c): return a + b + c # Overwrites first add()
add(1, 2) # Error! Only add(a,b,c) exists now
How to achieve function overloading in Python using different techniques?
Python achieves overloading-like behavior using:
1. Default Arguments:
def add(a, b, c=0): return a + b + c
add(1, 2) # Works
add(1, 2, 3) # Works
2. Variable Arguments:
def add(*args): return sum(args)
add(1, 2) # Works
add(1, 2, 3, 4) # Works
3. Type Checking:
def add(x, y):
    if isinstance(x, str): return x + y
    else: return x + y
What is the @singledispatch decorator for function overloading?
@singledispatch from functools provides generic function overloading based on the type of the first argument.
from functools import singledispatch

@singledispatch
def process(data):
    raise NotImplementedError("Unsupported type")

@process.register(int)
def _(data):
    return f"Processing integer: {data}"

@process.register(str)
def _(data):
    return f"Processing string: {data}"

print(process(10)) # "Processing integer: 10"
print(process("hi")) # "Processing string: hi"
What are destructors in Python and what is the __del__ method?
Destructors clean up resources when an object is destroyed. __del__ is called when an object is about to be garbage collected.
class Resource:
    def __init__(self, name):
        self.name = name
        print(f"{name} created")

    def __del__(self):
        print(f"{self.name} destroyed")

r = Resource("File")
del r # __del__ might be called (not guaranteed!)
Important: __del__ is not guaranteed to be called immediately! Rely on context managers (with statement) for resource cleanup.
Can we have multiple constructors in a Python class? How?
Yes, using @classmethod decorators as alternative constructors:
class Date:
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day

    @classmethod
    def from_string(cls, date_string): # Alternative constructor 1
        year, month, day = map(int, date_string.split('-'))
        return cls(year, month, day)

    @classmethod
    def from_timestamp(cls, timestamp): # Alternative constructor 2
        import datetime
        dt = datetime.fromtimestamp(timestamp)
        return cls(dt.year, dt.month, dt.day)

d1 = Date(2023, 12, 25) # Regular constructor
d2 = Date.from_string("2023-12-25") # Alternative constructor
d3 = Date.from_timestamp(1671926400) # Another alternative
What is constructor chaining in Python inheritance?
Constructor chaining calls parent class constructors from child class using super().
class Parent:
    def __init__(self, name):
        self.name = name
        print("Parent constructor")

class Child(Parent):
    def __init__(self, name, age):
        super().__init__(name) # Chain to parent constructor
        self.age = age
        print("Child constructor")

c = Child("Alice", 10)
# Output: "Parent constructor" then "Child constructor"
What happens if a Python class doesn't have an __init__ method?
If no __init__ is defined, Python uses the default constructor from the parent class (usually object). The object is created but not initialized with instance variables.
class SimpleClass:
    pass # No __init__

obj = SimpleClass() # Works fine
obj.value = 10 # Can add attributes dynamically
print(obj.value) # Output: 10
How to create immutable objects with __new__ method?
Use __new__ to control object creation, making objects immutable:
class ImmutablePoint:
    def __new__(cls, x, y):
        instance = super().__new__(cls)
        instance._x = x # Store in private attribute
        instance._y = y
        return instance

    @property
    def x(self):
        return self._x

    @property
    def y(self):
        return self._y

p = ImmutablePoint(3, 4)
print(p.x, p.y) # 3 4
# p.x = 10 # Error! Attribute is read-only
What is the difference between method overloading and method overriding?
Method Overloading:
Same method name, different parameters (NOT directly supported in Python).
Method Overriding:
Redefining parent class method in child class (SUPPORTED in Python).
class Parent:
    def display(self): # Parent method
        print("Parent display")

class Child(Parent):
    def display(self): # Overriding parent method
        print("Child display") # Different implementation

c = Child()
c.display() # Output: "Child display" (overridden)
How does Python handle multiple inheritance with constructors?
Python calls constructors based on Method Resolution Order (MRO). Use super() to call parent constructors properly:
class A:
    def __init__(self):
        print("A constructor")

class B:
    def __init__(self):
        print("B constructor")

class C(A, B):
    def __init__(self):
        super().__init__() # Calls A.__init__ (first in MRO)
        print("C constructor")

c = C()
# Output: "A constructor" then "C constructor"
What are factory methods and how are they related to constructors?
Factory methods are class methods that create and return instances, acting as alternative constructors.
class Shape:
    def __init__(self, sides):
        self.sides = sides

    @classmethod
    def triangle(cls): # Factory method
        return cls(3)

    @classmethod
    def square(cls): # Another factory method
        return cls(4)

t = Shape.triangle() # Creates triangle
s = Shape.square() # Creates square
print(t.sides) # 3
print(s.sides) # 4
Can constructors return values in Python?
No, __init__ cannot return values (except None). It must return None. However, __new__ can return any object.
# This is WRONG!
class WrongClass:
    def __init__(self):
        return 42 # Error! __init__ must return None
# __new__ can return different objects
class Singleton:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance # Returns existing instance
What is the purpose of *args and **kwargs in constructors?
*args captures positional arguments, **kwargs captures keyword arguments. They make constructors flexible:
class FlexibleClass:
    def __init__(self, *args, **kwargs):
        self.args = args
        self.kwargs = kwargs

obj1 = FlexibleClass(1, 2, 3) # args = (1, 2, 3)
obj2 = FlexibleClass(name="Alice", age=30) # kwargs = {'name': 'Alice', 'age': 30}
obj3 = FlexibleClass(1, 2, name="Bob") # Both args and kwargs
How to implement operator overloading with constructors?
Use special methods (not constructors) for operator overloading. Constructors create objects, while operator overloading defines behavior:
class Vector:
    def __init__(self, x, y): # Constructor
        self.x = x
        self.y = y

    def __add__(self, other): # Operator overloading for +
        return Vector(self.x + other.x, self.y + other.y)

    def __str__(self):
        return f"Vector({self.x}, {self.y})"

v1 = Vector(1, 2) # Constructor
v2 = Vector(3, 4) # Constructor
v3 = v1 + v2 # Operator overloading
print(v3) # Vector(4, 6)
What are metaclasses and how do they relate to constructors?
Metaclasses are classes of classes. They control class creation. __new__ and __init__ at metaclass level control class (not object) creation.
class Meta(type):
    def __new__(cls, name, bases, dct):
        print(f"Creating class {name}")
        return super().__new__(cls, name, bases, dct)

    def __init__(self, name, bases, dct):
        print(f"Initializing class {name}")
        super().__init__(name, bases, dct)

class MyClass(metaclass=Meta):
    def __init__(self):
        print("Object created")

# Output when MyClass is defined:
# "Creating class MyClass"
# "Initializing class MyClass"

obj = MyClass() # Output: "Object created"
How to create a singleton class using constructors?
Override __new__ to ensure only one instance is created:
class Singleton:
    _instance = None

    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

    def __init__(self, value=None):
        if value is not None:
            self.value = value

s1 = Singleton(10)
s2 = Singleton(20)
print(s1 is s2) # True (same instance)
print(s1.value) # 10 (first initialization)
print(s2.value) # 10 (not re-initialized)
Note: Key points about Python constructors and overloading: Python doesn't support traditional constructor/method overloading like Java/C++. Instead, use default arguments, variable arguments, class methods as alternative constructors, and @singledispatch for function overloading. Remember __new__ creates objects while __init__ initializes them. Always use super() for proper constructor chaining in inheritance.
Previous Python Constructors & Function Overloading Next