Python Constructors (__init__)

Module 3 • Session 23 • Object Lifecycle, Parameterized Initialization & Constructor Patterns

__init__ __new__ parameterized-constructors default-arguments classmethod-constructors

In Python, constructors are special dunder (double underscore) methods automatically executed when a new object instance is created. While languages like Java or C++ use the class name for constructors, Python uses the __init__() method to initialize the internal state of an object.

1. The Object Creation Lifecycle: `__new__` vs `__init__`

Creating an object in Python is a two-step process:

  1. __new__(cls, ...): Memory allocation step. It builds and returns a fresh, uninitialized instance of the class.
  2. __init__(self, ...): Initialization step. It receives the freshly created instance via self and sets up initial attributes.
class ExecutionTrace: def __new__(cls, *args, **kwargs): print("1. __new__ called: Allocating memory space for object instance.") instance = super().__new__(cls) return instance def __init__(self, name): print("2. __init__ called: Setting up state attributes.") self.name = name obj = ExecutionTrace("Compillo Engine")

2. Default vs Parameterized Constructors

Python supports default (non-parameterized) constructors as well as parameterized constructors that enforce explicit values upon instantiation.

# Default Constructor (No extra parameters beyond self) class SimpleLogger: def __init__(self): self.logs = [] self.is_active = True # Parameterized Constructor class UserProfile: def __init__(self, username, email, role="Member"): self.username = username self.email = email self.role = role # Parameter with default argument value user1 = UserProfile("alex_dev", "alex@example.com") user2 = UserProfile("admin_boss", "admin@example.com", role="Administrator") print(user1.role) # Output: Member print(user2.role) # Output: Administrator

3. Constructor Parameter Flexibility

You can utilize flexible positional and keyword argument traps inside __init__ to construct dynamic, highly adaptive classes.

Constructor Type Syntactic Signature Use Case & Characteristics
Default Constructor def __init__(self): Initializes fixed starting states without requiring external inputs.
Parameterized def __init__(self, arg1, arg2): Forces caller to pass initial state data on instantiation.
Default Arguments def __init__(self, name, status="Pending"): Provides optional parameters with fallback default choices.
Variadic (*args, **kwargs) def __init__(self, *args, **kwargs): Accepts dynamic arbitrary positional and key-value attributes.
Critical Warning — Mutable Default Arguments: Never write def __init__(self, items=[]):. Default parameter values are evaluated once when the function definition is executed. A mutable list or dictionary used as a default will be shared across all instances that rely on that default!
# WRONG (Shared mutable state bug) class FaultyCart: def __init__(self, items=[]): self.items = items # CORRECT (Fresh instance per object) class SafeCart: def __init__(self, items=None): if items is None: self.items = [] else: self.items = list(items)

4. Constructor Overloading & Alternative Constructors

Python does not support traditional method overloading where multiple __init__ definitions coexist in the same class. If you define multiple __init__ methods, the last definition will overwrite previous ones.

To achieve multiple ways to construct objects, Python uses @classmethod factory methods as alternative constructors.

import json class Employee: def __init__(self, name, salary, department): self.name = name self.salary = salary self.department = department # Alternative Constructor 1: Create from comma-separated string @classmethod def from_string(cls, emp_str): name, salary, dept = emp_str.split("-") return cls(name, float(salary), dept) # Alternative Constructor 2: Create from dictionary @classmethod def from_dict(cls, data_dict): return cls(data_dict["name"], data_dict["salary"], data_dict["department"]) # Standard creation e1 = Employee("John", 75000, "Engineering") # Creation using string factory e2 = Employee.from_string("Sarah-82000-Marketing") # Creation using dict factory e3 = Employee.from_dict({"name": "David", "salary": 90000, "department": "Data Science"}) print(e2.name, e2.department) # Sarah Marketing print(e3.name, e3.salary) # David 90000.0

5. Comprehensive End-to-End Example: Database Connection Pool

Below is a complete enterprise pattern demonstrating parameter validation, default settings, dynamic connection string parsing, and state setup inside a constructor:

class DatabaseConnection: def __init__(self, host="localhost", port=5432, db_name="main_db", timeout=30): if not isinstance(port, int) or port <= 0: raise ValueError("Port must be a positive integer.") self.host = host self.port = port self.db_name = db_name self.timeout = timeout self.is_connected = False self.connection_string = f"postgresql://{self.host}:{self.port}/{self.db_name}" @classmethod def from_url(cls, url): # Example URL parsing: postgresql://admin:5432/production clean_url = url.replace("postgresql://", "") host_port, db = clean_url.split("/") host, port = host_port.split(":") return cls(host=host, port=int(port), db_name=db) def connect(self): self.is_connected = True print(f"Connected to '{self.db_name}' at {self.host}:{self.port} (Timeout: {self.timeout}s)") # Usage db_default = DatabaseConnection() db_default.connect() db_custom = DatabaseConnection.from_url("postgresql://192.168.1.50:5433/analytics") db_custom.connect()

🏋️ Try It Yourself: Practice Challenges

Challenge 1: Safe Inventory Item

Create an `InventoryItem` class with `__init__` that sets `name`, `quantity` (default 0), and `tags` (default `None`). Avoid mutable default parameter bugs.

Challenge 2: Color Model Factory

Build a `Color` class with `__init__(self, red, green, blue)`. Add an alternative `@classmethod` called `from_hex(cls, hex_code)` that converts string hex codes like `"#FF0000"` into RGB integer values.

Challenge 3: Constructor Validation

Write a `BankAccount` constructor that accepts `owner` and `balance`. Raise a `ValueError` inside `__init__` if the initial balance parameter is negative.

⚡ Interactive Sandbox (Python Constructors)
Console Output:
Click "Run Code" above to execute scripts...

📝 Knowledge Check Quiz

1. Which dunder method is primarily responsible for allocating memory before initial instance setup?
2. Why should you avoid defining `def __init__(self, data=[]):`?
3. How do Python developers implement multiple initialization formats without standard constructor overloading?
Advertisement
Horizontal Ad Banner Slot (728x90 / Responsive)