Python Notes
Deep dive into Python constructors — __init__, __new__, default parameters, class method constructors, constructor chaining, and destructor __del__ with real-world examples.
🧠 Real-World Analogy — Hotel Check-In
When you check into a hotel, the receptionist has you fill out a form — name, ID, room preference. Filling out this form is the constructor. Until the form is filled, you don't get a room key. Similarly, until the constructor runs, the object doesn't have its initial data. A constructor is a special method that runs automatically as soon as an object is created and sets its initial state.
📐 ASCII Diagram — Object Lifecycle
✅ Example 1 — Basic __init__
class Person:
def __init__(self, name, age, city="Unknown"):
self.name = name
self.age = age
self.city = city
print(f"✅ Person created: {self.name}")
def greet(self):
print(f"Hello! I'm {self.name}, {self.age} years old from {self.city}.")
# Creating objects
p1 = Person("Arjun", 25, "Delhi")
p2 = Person("Priya", 22, "Mumbai")
p3 = Person("Ravi", 30) # city defaults to "Unknown"
p1.greet()
p2.greet()
p3.greet()Output:
| ✅ Person created | Arjun |
| ✅ Person created | Priya |
| ✅ Person created | Ravi |
⚙️ Default Arguments in Constructor
class Rectangle:
def __init__(self, length=1, width=1, color="white"):
self.length = length
self.width = width
self.color = color
def area(self):
return self.length * self.width
def perimeter(self):
return 2 * (self.length + self.width)
def describe(self):
print(f"{self.color.capitalize()} rectangle: {self.length}x{self.width} "
f"| Area={self.area()} | Perimeter={self.perimeter()}")
r1 = Rectangle() # all defaults
r2 = Rectangle(5, 3) # positional
r3 = Rectangle(10, 6, "blue") # positional
r4 = Rectangle(color="red", length=8, width=4) # keyword
r1.describe()
r2.describe()
r3.describe()
r4.describe()Output:
| White rectangle | 1x1 | Area=1 | Perimeter=4 |
| White rectangle | 5x3 | Area=15 | Perimeter=16 |
| Blue rectangle | 10x6 | Area=60 | Perimeter=32 |
| Red rectangle | 8x4 | Area=32 | Perimeter=24 |
🏭 Alternate Constructors with @classmethod
In Python, constructor overloading (same name, different signature) isn't directly possible like in Java/C++. But we can create factory methods using @classmethod — providing alternative ways to create objects.Output:
🏗️ Constructor Chaining with super()
Output:
🔒 Singleton Pattern with __new__
The Singleton pattern ensures that only one object of a class can ever exist — useful for system-wide configuration or database connections.
Output:
🗑️ Destructor __del__
class FileHandler:
def __init__(self, filename):
self.filename = filename
self.file = open(filename, "w")
print(f"📂 Opened file: {filename}")
def write(self, text):
self.file.write(text + "\n")
def __del__(self):
if not self.file.closed:
self.file.close()
print(f"🗑️ FileHandler for '{self.filename}' destroyed, file closed.")
handler = FileHandler("temp_output.txt")
handler.write("Hello, World!")
handler.write("Python OOP is awesome!")
del handler # triggers __del__
print("Program continues...")Output:
⚠️ Best Practice: Preferwithstatement (context managers) over__del__for resource cleanup.__del__timing is not guaranteed.
🧪 Example — Student with Validation
Output:
| [STU0001] Arjun Sharma Roll | 0001 Marks: 92 Grade: A+ |
| [STU0002] Priya Mehta Roll | 0002 Marks: 85 Grade: A |
| [STU0003] Rahul Verma Roll | 0003 Marks: 73 Grade: B |
| [STU0004] Sneha Kapoor Roll | 0004 Marks: 61 Grade: C |
| [STU0005] Vikas Singh Roll | 0005 Marks: 38 Grade: F |
| Total students enrolled | 5 |
| ❌ Validation Error | Name must be a non-empty string. |
🇮🇳 Hindi Explanation (हिंदी में समझें)
What does a constructor do? A constructor is a special method that is automatically called as soon as an object is created. Its job is to set the object's initial state — assigning default or given values to attributes.
What is the difference between__init__and__new__?__new__allocates memory (creates a new object), while__init__initializes that object (fills in values). We usually only write__init__.
Why do we use alternate constructors? Because Python doesn't have constructor overloading. If you want to create objects from different formats (string, dict, date), you create named constructors using @classmethod.Destructor__del__kab call hota hai? When an object's reference count reaches zero, Python automatically calls__del__. But its exact timing isn't guaranteed, so usewithstatements (context managers) for resource cleanup instead.
❓ Interview Questions
Q1: What is the difference between __init__ and __new__?
Answer:
__new__is called first and creates the object (allocates memory). It receives the class as the first argument and returns the new instance.__init__is called second to initialize the newly created object. It receives the instance (self) and sets up attributes.
Most developers only override __init__. __new__ is used for immutable types (like int, str) or Singleton patterns.
Q2: Does Python support constructor overloading?
Answer: Not directly. Unlike Java/C++, Python cannot have multiple __init__ methods with different signatures. Workarounds:
- Default arguments:
def __init__(self, x, y=0, z=0) - **
*args/kwargs: accept variable arguments @classmethodfactory methods:Date.from_string("15-08-1947")
Q3: Why is @classmethod used for alternate constructors?
Answer: @classmethod receives the class (cls) as the first argument rather than an instance. This lets it call cls(...) to create and return a new instance, acting as a named factory. This is more maintainable than __init__ with complex branching.
Q4: What is a destructor? When is __del__ called?
Answer: __del__ is the destructor method, called when an object's reference count drops to zero. Python's garbage collector then reclaims memory. Timing is not guaranteed (especially in CPython with cyclic references), so it should NOT be relied on for critical cleanup — use context managers (with) instead.
Q5: How can you prevent a class from being instantiated more than once (Singleton)?
Answer: Override __new__:
class Singleton:
_instance = None
def __new__(cls, *a, **kw):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instanceQ6: What happens if __init__ raises an exception?
Answer: The object is created by __new__ but __init__ fails. The incomplete object has no name binding (the variable is never assigned), so it becomes immediately eligible for garbage collection. The exception propagates to the caller.
🧪 Practice Exercises
- Config Manager (Singleton): Create a
Configclass that can only have one instance and stores key-value settings. - Vector3D: Create a
Vector3D(x, y, z)class with alternate constructors:from_list([1,2,3]),from_dict({"x":1,"y":2,"z":3}), andzero()(returns origin vector). - Employee: Create an
Employeeclass with validation —namemust be non-empty,salarymust be positive,departmentmust be one of a predefined list. - Timer: Create a
Timerclass whose__del__prints how long the object existed (usetime.time()in__init__and__del__). - Pizza Builder: Create a
Pizzaclass with afrom_size(size)classmethod that sets default toppings based on pizza size.
💡 Next Topic → Inheritance: Learn how classes inherit attributes and methods, use super(), and build powerful class hierarchies.Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Constructors in Python.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Python Master Course topic.
Search Terms
python-master-course, python master course, python, master, course, object, oriented, programming
Related Python Master Course Topics