Python Tutorial
Constructors and the __init__ Method
When you create an object, Python calls special methods to build it: __new__ creates the object and __init__ initialises its attributes. __init__ is what most people call the "constructor". It is where you set starting values, validate arguments, and establish the invariants the rest of the class relies on.
This lesson covers __init__ with required and default parameters, validation, alternative constructors with @classmethod, calling a parent's constructor with super(), __new__ for special cases, and the destructor __del__.
The __init__ Method
__init__(self, ...) runs automatically after the object is created. It should set every attribute the object needs, so objects are never half-initialised. It must return None. Python does not support multiple constructors by overloading; use default arguments or alternative constructors instead.
Validation in the Constructor
Checking arguments in __init__ and raising ValueError or TypeError for bad input means an invalid object can never exist. It is far easier to debug an error at creation time than a wrong value discovered much later.
Alternative Constructors
A @classmethod that returns cls(...) gives a class several named ways to be created: Date.from_string("2026-09-27"), User.from_dict(data). This is Python's answer to constructor overloading and keeps __init__ simple.
__new__ and __del__
__new__(cls, ...) actually allocates the object; override it only for immutable subclasses (like subclasses of str or tuple) or patterns such as singletons. __del__ runs when an object is garbage-collected, but the timing is not guaranteed — use context managers (with) for reliable cleanup.
Examples
A constructor with defaults and validation
class Product:
def __init__(self, name, price, quantity=0):
if not name:
raise ValueError("name is required")
if price < 0:
raise ValueError("price cannot be negative")
self.name = name
self.price = price
self.quantity = quantity
def total(self):
return self.price * self.quantity
pen = Product("Pen", 10, 5)
book = Product("Book", 250)
print(pen.total(), book.quantity)
for args in [("", 10), ("Bag", -5)]:
try:
Product(*args)
except ValueError as e:
print("ValueError:", e)
50 0
ValueError: name is required
ValueError: price cannot be negative
Alternative constructors with @classmethod
class Student:
def __init__(self, name, age, city):
self.name, self.age, self.city = name, age, city
@classmethod
def from_csv(cls, line):
name, age, city = line.split(",")
return cls(name.strip(), int(age), city.strip())
@classmethod
def from_dict(cls, data):
return cls(data["name"], data.get("age", 0), data.get("city", "Unknown"))
def __repr__(self):
return f"Student({self.name!r}, {self.age}, {self.city!r})"
print(Student("Asha", 24, "Pune"))
print(Student.from_csv("Ravi, 30, Delhi"))
print(Student.from_dict({"name": "Meera"}))
Student('Asha', 24, 'Pune')
Student('Ravi', 30, 'Delhi')
Student('Meera', 0, 'Unknown')
Calling the parent constructor with super()
class Person:
def __init__(self, name):
self.name = name
class Employee(Person):
def __init__(self, name, salary):
super().__init__(name) # let Person initialise its part
self.salary = salary
e = Employee("Kiran", 50000)
print(e.name, e.salary)
Kiran 50000
__new__ for a singleton and __del__
class Config:
_instance = None
def __new__(cls):
if cls._instance is None:
print("creating the single Config")
cls._instance = super().__new__(cls)
return cls._instance
a, b = Config(), Config()
print(a is b)
class TempFile:
def __init__(self, name):
self.name = name
print("open", name)
def __del__(self):
print("cleanup", self.name)
t = TempFile("report.tmp")
del t
print("done")
creating the single Config
True
open report.tmp
cleanup report.tmp
done
Common Mistakes
- Misspelling __init__ (e.g. _init_ or __int__), so it never runs.
- Returning a value from __init__ (TypeError).
- Defining two __init__ methods expecting overloading — the second replaces the first.
- Forgetting super().__init__() in a subclass, leaving parent attributes unset.
- Relying on __del__ for important cleanup instead of context managers.
Key Points to Remember
- __init__ initialises a new object; __new__ creates it.
- Validate arguments in __init__ so invalid objects never exist.
- Use @classmethod alternative constructors instead of overloading.
- Call super().__init__() in subclasses.
- Prefer context managers over __del__ for cleanup.
Practice the examples
Change an input, predict the result, then compare it with the output. Explain why the result changes.