Object Initialisation With Constructors
A constructor is the special method Python runs automatically when you create a new object. In Python it is called __init__. This chapter shows you the full life-cycle of an object, the role of __new__ and __init__, default and parameterised constructors, and the patterns professional developers use to initialise objects safely.
Overview
Auto-Triggered
Runs the moment you create an instance — no extra call needed.
Custom State
Set all needed attributes in one place.
Defaults
Accept optional arguments with default values.
Parent Calls
super().__init__() chains construction up the hierarchy.
Validation
Reject bad input early — raise exceptions inside the constructor.
Syntax
- Define with
def __init__(self, ...):. - Python calls it automatically when you do
obj = MyClass(args). - Use
self.attribute = valueto set instance state. - Use
super().__init__()to invoke a parent class constructor.
class Person:
def __init__(self, name, age=0):
self.name = name
self.age = age
class Employee(Person):
def __init__(self, name, age, salary):
super().__init__(name, age)
self.salary = salary
emp = Employee("Riya", 25, 50000)
print(emp.name, emp.age, emp.salary)
Detailed Explanation
- Why constructors matter: Constructors guarantee every new object starts in a valid state. They eliminate the need to manually set attributes after creation.
- Default constructor: If you don't define
__init__, Python provides a no-arg default that does nothing extra. - Parameterised constructor: Accepts arguments and assigns them to
self. Most real classes have one. - Default values: Provide defaults in the signature:
def __init__(self, x=0, y=0). Optional, named, and clean. - super().__init__(): In a subclass, call the parent constructor to inherit its initialisation. Forgetting this is a common bug.
- __new__ vs __init__:
__new__creates the object (rare to override).__init__initialises it (you override this constantly).
Code Examples
class Greeting:
def __init__(self, name="World"):
self.name = name
def hello(self):
return f"Hello, {self.name}!"
print(Greeting().hello())
print(Greeting("PBA").hello())
Hello, PBA!
class Age:
def __init__(self, value):
if value < 0:
raise ValueError("Age cannot be negative")
self.value = value
try:
a = Age(-5)
except ValueError as e:
print(e)
class Widget:
count = 0
def __init__(self, label):
Widget.count += 1
self.id = Widget.count
self.label = label
for lbl in ["A", "B", "C"]:
print(Widget(lbl).id)
2
3
class Vehicle:
def __init__(self, brand):
self.brand = brand
class Car(Vehicle):
def __init__(self, brand, model):
super().__init__(brand)
self.model = model
c = Car("Honda", "Civic")
print(c.brand, c.model)
class Box:
def __init__(self, w=1, h=1, d=1):
self.w, self.h, self.d = w, h, d
def volume(self):
return self.w * self.h * self.d
print(Box().volume())
print(Box(2, 3).volume())
print(Box(2, 3, 4).volume())
6
24
class Singleton:
_inst = None
def __new__(cls):
if cls._inst is None:
cls._inst = super().__new__(cls)
return cls._inst
a, b = Singleton(), Singleton()
print(a is b)
Real-World Use Cases
User Setup
Initialise user objects with username, password hash, and timestamps.
DB Connections
Establish the connection inside the constructor of a DB wrapper.
File Readers
Open the file in __init__ so the reader is ready to use.
Auth Tokens
Generate or validate token state during object creation.
Pricing Rules
Receive base price and discount; store calculated final price.
Configuration Objects
Validate settings up-front before the app runs.
Notes & Pro Tips
- Always initialise every attribute the class will use — avoid 'maybe-set' attributes.
- Validate inputs early; raise meaningful exceptions if invalid.
- Call
super().__init__()in subclasses to keep parent invariants. - Avoid heavy work in constructors — keep them quick and predictable.
- Use
@dataclasswhen you mostly assign attributes from arguments. __new__is rarely needed; reach for it only for singletons, immutable subclasses, or metaclasses.
Common Mistakes
- Forgetting
self: turns the constructor into an unbound function. - Missing
super().__init__(): parent state remains uninitialised. - Mutable default arguments: shared between instances, surprising bugs.
- Doing too much in
__init__: hides slow operations like DB / IO; consider factories. - Returning a value from
__init__: raisesTypeError; only__new__can return. - Confusing class and instance scope: assignments inside
__init__must useself..
Practice Problems
- Problem 1: Create a class
Bookwith a parameterised constructor taking title, author, price. - Problem 2: Build a
Triangleclass whose constructor validates that three sides form a valid triangle. - Problem 3: Make a class
Counterthat tracks how many instances have been created. - Problem 4: Design a
Personclass and a subclassStudentthat uses super(). - Problem 5: Write a
Rectangleclass with defaults length=1, width=1 and method area(). - Problem 6: Implement a Singleton class using
__new__.
Interview Questions
- Q1. What is a constructor and when is it called?
- Q2. What is the difference between
__init__and__new__? - Q3. Can
__init__return a value? - Q4. What happens if a subclass doesn't call
super().__init__()? - Q5. Does Python support constructor overloading?
- Q6. How do you implement default arguments in a constructor?
Frequently Asked Questions
- Q1: What is __init__?
It is the constructor method called automatically when you create an object. It initialises the instance's attributes. - Q2: What is __new__?
__new__ is responsible for allocating and returning the new instance. It runs before __init__. You rarely override it. - Q3: Does Python have constructor overloading?
Not directly. Use default arguments, *args/**kwargs, or classmethod factories to achieve similar behaviour. - Q4: Can a constructor return a value?
No — __init__ must return None. Only __new__ may return the object itself. - Q5: Why call super().__init__()?
To run the parent class's constructor so its state is initialised. Forgetting it can cause subtle bugs. - Q6: What is a default constructor?
An __init__ with no parameters (other than self) — or the implicit one Python supplies when you don't define one.
Summary
The constructor __init__ is your chance to set up a new object before any other code touches it. Use it to assign attributes, validate inputs, call super().__init__(), and otherwise place the object in a known-good state. Keep it small, predictable, and free of heavy side-effects — your future self will thank you when the codebase grows.
Continue Learning
Previous
Go to Previous Chapter