Python Constructors
A complete beginner-friendly guide to constructors in Python โ covering __init__, default and parameterized constructors, __new__ vs __init__, constructor chaining with super(), and real-world object-initialisation patterns for 2026.
Last Updated
March 2026
Read Time
27 min
Level
Beginner
What is a Constructor in Python?
A constructor is a special method that runs automatically whenever a new object is created from a class. Its job is to set up the object's initial state โ assigning starting values to its attributes so the object is immediately ready to use. In Python, this role is filled by the special method __init__, short for "initialise".
Think of a constructor as the setup crew that prepares a new house the moment it's built โ connecting the electricity, installing the doors, and making sure the address plate is fitted before anyone moves in. Without a constructor, an object would exist as an empty shell with no attributes, forcing you to set every single value manually after creation, one line at a time.
It's worth clarifying a subtle but important technical detail: in Python, __init__ does not actually create the object โ it only initialises one that already exists. The true creation step is handled by a separate, rarely-overridden method called __new__. This two-step design (allocate, then initialise) is different from languages like Java or C++, where the constructor handles both jobs in a single step.
Every class in Python has a constructor, even if you never write one yourself. If you don't define __init__, Python quietly uses a default one inherited from the built-in object class, which simply creates an empty object with no custom attributes. Defining your own __init__ is how you take control of what happens the instant an object comes into being.
How Constructors Evolved in Python
Python's constructor mechanism has stayed conceptually stable since the language's earliest days, but the details around it have been refined significantly as Python matured. Here is a timeline of the key milestones:
- โถ
1991 โ Python 0.9.0 already supported __init__ as the initialisation method for classes, borrowing the underlying idea of automatic object setup from languages like Modula-3.
- โถ
1995-2000 โ Early Python versions used 'classic classes,' where __init__ behaviour was slightly inconsistent between classes that inherited from built-in types and those that didn't.
- โถ
2001 โ Python 2.2 unified classic and new-style classes, formally separating object creation (__new__) from initialisation (__init__) as two distinct, overridable special methods for every class.
- โถ
2008 โ Python 3.0 made new-style classes the only option โ every class now inherits from object automatically, guaranteeing __new__ and __init__ behave consistently everywhere.
- โถ
2015 โ PEP 484 introduced type hints, letting constructor parameters be annotated, e.g. def __init__(self, brand: str, speed: int = 0) -> None:, improving editor autocomplete and static analysis.
- โถ
2018 โ Python 3.7's @dataclass decorator (PEP 557) began auto-generating __init__ methods entirely from type-annotated class attributes, removing repetitive constructor boilerplate.
- โถ
2021 โ Python 3.10 added keyword-only dataclass fields and improved error messages when constructor arguments were missing or mismatched, making debugging faster.
- โถ
2022-2026 โ Python 3.11 through 3.14 focused on making constructor calls and attribute initialisation faster at the interpreter level, alongside continued refinement of typing.Self for constructors that return builder-style instances.
Types of Constructors in Python
Python doesn't have rigid, named constructor categories the way some languages do, but constructors are commonly grouped into a few practical patterns based on how they behave. Here are the core types every developer should recognise:
An __init__ that takes no parameters besides self, or a class with no __init__ at all. It creates an object with no custom setup, or with fixed, hard-coded starting values.
An __init__ that accepts arguments beyond self, letting each object be initialised with different starting values, e.g. Car('Tesla', 'Model 3').
A parameterized constructor where some parameters have default values, e.g. def __init__(self, brand, speed=0):, making those arguments optional at call time.
A subclass constructor that calls its parent class's __init__ using super(), reusing the parent's setup logic before adding its own.
A class method that acts as a second, differently-named way to build an object, often used to construct instances from strings, files, or dictionaries.
The lower-level method actually responsible for allocating a new object in memory, called automatically before __init__. Rarely overridden except for advanced patterns like singletons.
Python has no true private constructors, but developers simulate the effect using naming conventions or by raising exceptions inside __init__ to block direct instantiation.
Python has no built-in copy constructor keyword; developers achieve similar behaviour using the copy module (copy.copy() or copy.deepcopy()) or a custom classmethod.
An __init__ automatically generated by the @dataclass decorator based purely on type-annotated class attributes, eliminating manual boilerplate.
How a Constructor Executes โ Flowchart
It helps enormously to see the exact sequence Python follows when a constructor runs. The flowchart below traces every step from the moment you call Car("Tesla", "Model 3") to the moment a fully initialised object is handed back to your code.
Code Execution Flow โ from source to output
Key insight: __init__ always returns None, even implicitly. If you ever write return something inside __init__, Python raises a TypeError: __init__() should return None. This is a direct consequence of the two-step design โ __init__'s only job is to modify an object that already exists, never to produce a new one.
How Python Constructors Work โ __init__, __new__, and self Explained
To truly understand constructors, you need to separate two ideas that are often blurred together: creating an object and initialising it. Python treats these as two distinct steps handled by two distinct special methods.
๐งฑ __new__ โ The Real Object Creator
__new__ is a static method (though you never mark it with @staticmethod โ Python treats it specially) responsible for allocating memory and returning a brand-new, empty instance of the class. It is called automatically before __init__, and it receives the class itself (cls) as its first argument, not an already-existing object, because at this point no object exists yet. Almost every Python developer goes years without ever needing to override __new__ โ it is reserved for advanced patterns like immutable types, singletons, or metaclass-level control.
๐ง __init__ โ The Initialiser
Once __new__ has produced a bare object, Python automatically calls __init__ on it, passing that same object in as self. This is where you assign starting values to instance attributes โ self.brand = brand, self.speed = speed, and so on. Everything you write inside __init__ operates on an object that Python has already created for you; your only responsibility is to fill it in correctly.
๐ Why self Appears in Every Constructor
Just like every other instance method, __init__ takes self as its first parameter so it knows exactly which object it is initialising. When you write Car("Tesla", "Model 3"), Python internally performs roughly the equivalent of: create a new object via __new__, then call Car.__init__(new_object, "Tesla", "Model 3"). The variable you assign the result to โ car1 = Car(...) โ simply captures a reference to that finished object.
๐๏ธ Default Values Make Parameters Optional
Constructor parameters can have default values just like any Python function, e.g. def __init__(self, brand, model, speed=0):. This lets callers omit speed entirely when creating a car with zero starting speed, while still requiring brand and model to be supplied. A common and important rule: parameters with default values must come after parameters without them, otherwise Python raises a SyntaxError.
๐ Constructor Chaining with super().__init__()
When a subclass defines its own __init__, it does not automatically run the parent class's __init__ โ you must call it explicitly using super().__init__(...). This lets a subclass reuse the parent's initialisation logic (like setting shared attributes) before adding its own specialised setup, avoiding duplicated code across a class hierarchy.
Simple rule to remember: __new__ creates the empty object. __init__ fills it in. self identifies which object is being filled in. super().__init__() reuses a parent's fill-in logic inside a child class.
__new__ vs __init__ โ Key Differences
Beginners frequently confuse these two methods since both run automatically during object creation. This table lays out exactly how they differ.
Python Constructors vs Other Languages โ Comparison
Every major object-oriented language has some form of constructor, but the syntax and rules differ noticeably. This table compares how constructors work across popular languages.
Advantages and Limitations of Python Constructors
Constructors make object initialisation predictable and consistent, but Python's particular approach comes with a few trade-offs worth understanding.
Constructor Architecture โ From Class Definition to Live Object
The diagram below shows how the different constructor-related pieces of a class fit together, from the outermost class declaration down to the finished object sitting in memory.
Your First Python Constructor โ A Complete Example
Below is a complete example showing a default constructor, a parameterized constructor, and default arguments working together in a single, realistic Car class.
class Car:
def __init__(self, brand="Unknown", model="Unknown", speed=0):
# Parameterized constructor with default arguments
self.brand = brand
self.model = model
self.speed = speed
print(f"Constructor called for {self.brand} {self.model}")
def show(self):
print(f"{self.brand} {self.model} โ {self.speed} km/h")
# Default-style call โ uses all default values
car1 = Car()
# Parameterized call โ overrides defaults
car2 = Car("Tesla", "Model 3", 60)
car1.show()
car2.show()Output
Constructor called for Unknown Unknown Constructor called for Tesla Model 3 Unknown Unknown โ 0 km/h Tesla Model 3 โ 60 km/hPractice This Code โ Live Editor
Line-by-Line Explanation
- โถ
def __init__(self, brand="Unknown", model="Unknown", speed=0):โ A single constructor handling both default and parameterized creation, thanks to default argument values. - โถ
self.brand = brandโ Assigns the passed-in (or default) value to this specific object's brand attribute. - โถ
print(f"Constructor called for...")โ Demonstrates that __init__ runs automatically and immediately, without you ever calling it directly. - โถ
car1 = Car()โ Calls the constructor with zero arguments; every parameter falls back to its default value. - โถ
car2 = Car("Tesla", "Model 3", 60)โ Calls the same constructor, but this time supplying explicit values that override every default. - โถ
car1.show()โ A regular instance method, unrelated to the constructor, used here just to display the finished object's state.
Constructor Chaining โ super().__init__() in Inheritance
When a subclass has its own constructor, it should almost always call its parent's constructor first using super().__init__(), so the parent's setup logic still runs. Skipping this step is one of the most common beginner mistakes in inheritance.
class Vehicle:
def __init__(self, brand):
self.brand = brand
print(f"Vehicle constructor: brand set to {brand}")
class Car(Vehicle):
def __init__(self, brand, model, speed=0):
super().__init__(brand) # Calls Vehicle's constructor first
self.model = model
self.speed = speed
print(f"Car constructor: model set to {model}")
car1 = Car("Tesla", "Model 3")Output
Vehicle constructor: brand set to Tesla Car constructor: model set to Model 3Notice the order of output: the parent's constructor runs first, then the child's. This mirrors real-world assembly โ you build the general foundation before adding specialised details on top of it. If super().__init__(brand) were removed, self.brand would never be set, and accessing car1.brand later would raise an AttributeError.
Alternative Constructors Using @classmethod
Since Python doesn't support true constructor overloading, developers commonly use @classmethod to provide additional, clearly-named ways to build an object โ a pattern often called a "factory method."
class Car:
def __init__(self, brand, model):
self.brand = brand
self.model = model
@classmethod
def from_string(cls, car_string):
brand, model = car_string.split("-")
return cls(brand, model) # Calls the normal constructor
car1 = Car("Tesla", "Model 3")
car2 = Car.from_string("Toyota-Corolla")
print(car1.brand, car1.model)
print(car2.brand, car2.model)Output
Tesla Model 3 Toyota CorollaHere, from_string acts as a second constructor tailored for a specific input format, while internally still relying on the standard __init__ to actually build the object. This pattern is used extensively in real frameworks โ for instance, datetime.fromtimestamp() and dict.fromkeys() are both alternative constructors built exactly this way.
Where Constructors Are Used โ Real-World Applications
Constructors aren't just a textbook concept โ they are working behind the scenes every time you use a Python object, library, or framework. Here's where they show up in practice:
- โถ
๐ Django Model Instances โ Every time you write User.objects.create(name='Alice'), Django's model constructor runs, setting up a new row-representing object with the fields you specify.
- โถ
๐ง Machine Learning Model Setup โ In PyTorch, a neural network's __init__ method is where every layer (nn.Linear, nn.Conv2d) is defined and attached to the model object before training even begins.
- โถ
๐ฆ Financial Object Validation โ A BankAccount constructor commonly validates that an initial deposit isn't negative, rejecting invalid objects the moment they're created rather than letting bad data slip through later.
- โถ
๐ Parsing Data into Objects โ Alternative constructors like from_json() or from_csv_row() are extremely common in data-processing code, converting raw external data directly into structured Python objects.
- โถ
๐ Database Connection Objects โ Libraries like SQLAlchemy and psycopg2 use constructors to set up connection parameters (host, port, credentials) the moment a connection object is created.
- โถ
๐ฎ Game Entity Initialisation โ In Pygame projects, a Player or Enemy constructor typically sets starting health, position, and sprite image, ensuring every game entity begins in a valid, ready-to-render state.
- โถ
โ๏ธ Cloud SDK Clients โ Calling boto3.client('s3') runs a constructor internally that sets up authentication, region, and retry configuration before you make a single API call.
- โถ
๐งช Test Fixture Setup โ In testing frameworks, constructors are often used to build fully-configured mock objects with known starting states for reliable, repeatable unit tests.
Why Should You Master Constructors in 2026?
Constructors sit at the very entry point of every object's life. Getting them right โ or wrong โ ripples through everything that object does afterward. Here's why they deserve careful attention:
- โถ
๐ก๏ธ Prevents Invalid Objects โ A well-designed constructor can validate inputs immediately, stopping broken or nonsensical objects from ever existing in your program in the first place.
- โถ
๐ Required to Read Any Real Codebase โ Nearly every Python class you'll encounter professionally defines a custom __init__, so understanding constructors is non-negotiable for reading and contributing to real projects.
- โถ
๐งฉ Foundation for Inheritance โ Constructor chaining with super().__init__() is essential to understand before tackling more advanced inheritance and polymorphism topics.
- โถ
๐ผ Common Interview Topic โ Questions about __new__ vs __init__, mutable default arguments, and constructor chaining appear frequently in Python developer interviews at every level.
- โถ
๐ญ Unlocks Design Patterns โ Factory methods, singletons, and builder patterns all revolve around controlling how and when constructors run โ understanding this deeply opens the door to cleaner architecture.
- โถ
๐ Speeds Up Debugging โ A huge share of 'why is this attribute missing' bugs trace back to constructor logic โ forgotten super() calls, wrong parameter order, or shared mutable defaults.
Python Versions and Constructor-Related Features
Constructor mechanics have evolved gradually across Python's history. Here's a quick reference of the version-specific milestones relevant to how constructors are written today:
- โถ
Python 2.2 โ __new__ Formally Separated โ Established the clean split between object creation (__new__) and initialisation (__init__) that every modern Python class relies on.
- โถ
Python 3.0 โ Universal New-Style Classes โ Guaranteed every class, including built-in subclasses, follows the same consistent __new__/__init__ construction process.
- โถ
Python 3.5 โ Type Hints for Parameters โ PEP 484 allowed constructor parameters to carry type annotations, e.g. def __init__(self, brand: str), improving editor support without changing runtime behaviour.
- โถ
Python 3.7 โ @dataclass Auto-Generated __init__ โ Introduced automatic constructor generation from annotated class attributes, removing manual boilerplate for simple data classes entirely.
- โถ
Python 3.8 โ Positional-Only Parameters โ Added the / syntax, letting constructor authors mark certain parameters as positional-only, preventing callers from passing them as keyword arguments.
- โถ
Python 3.10 โ Keyword-Only Dataclass Fields โ kw_only=True lets dataclass-generated constructors require certain fields to be passed by keyword, improving clarity for classes with many parameters.
- โถ
Python 3.11-3.14 โ Performance & Self Typing โ Faster object allocation and improved typing.Self support made constructor-heavy code both quicker to run and easier to type-check accurately.
Python Constructors โ Interview Questions (Beginner Level)
These are the most frequently asked interview questions about Python constructors for freshers and beginner-level positions. Review these carefully before your next Python interview.
Practice Questions โ Test Your Understanding
Test your grasp of Python constructors with these practice questions. Try answering each one yourself before checking the answer โ active recall builds much stronger, longer-lasting understanding than passive reading.
1. What error occurs if you write 'return self' inside __init__, and why?
Easy2. If a subclass forgets to call super().__init__(), what specific problem can occur?
Medium3. Why does def __init__(self, items=[]): cause a subtle bug across multiple objects?
Hard4. What is the correct order in which __new__ and __init__ are called, and what does each receive as its first argument?
Medium5. How would you prevent a class from being instantiated directly, forcing users to go through an alternative constructor instead?
Hard6. What does cls(brand, model) do inside a @classmethod alternative constructor?
Medium7. Why must default-valued parameters come after non-default parameters in a constructor?
Easy8. How does a @dataclass-generated __init__ differ from one you write manually, in terms of what it can do?
HardConclusion โ Why Constructors Matter
Constructors are the entry point to an object's entire lifecycle. Get them right, and every object your class produces starts out valid, predictable, and ready to use. Get them wrong, and subtle bugs โ shared mutable defaults, missing parent attributes, silently broken inheritance โ can ripple through an entire codebase.
The concepts covered here โ __init__ as the initialiser, __new__ as the true object creator, default and parameterized constructors, constructor chaining with super(), and alternative constructors via @classmethod โ together form a complete picture of how Python brings objects into existence.
The natural next step after mastering constructors is Inheritance and Polymorphism โ building on constructor chaining to understand how entire families of related classes can share and extend initialisation logic cleanly. From there, encapsulation, dunder methods, and classic design patterns all build naturally on the foundation laid here.
A well-designed constructor is the difference between an object that is trustworthy from the moment it's born and one that quietly causes problems later. Practice writing your own __init__ methods, experiment with default arguments and super(), and the concept will click quickly. ๐๏ธ