How to create an instance of a class in Python
Create a class instance in Python. This guide covers methods, tips, real-world uses, and debugging common errors.

Class instantiation is a fundamental concept in Python's object-oriented programming. This process lets you create unique objects from a class blueprint, which is essential for modular application design.
In this article, you'll explore various instantiation techniques and practical tips. You'll also find real-world applications and debugging advice to help you confidently use classes in your own projects.
Basic class instantiation
class Person:
def __init__(self, name):
self.name = name
person = Person("Alice")
print(person.name)--OUTPUT--Alice
The Person class uses the special __init__ method, which acts as its constructor. When you call Person("Alice"), you're not just creating an object—you're also triggering this setup method to initialize its state.
- The
__init__method receives the new instance (asself) and the argument"Alice". - It then assigns this value to the instance's
nameattribute, giving the object its initial data.
This process ensures every Person object you create is properly configured with its own unique attributes from the moment it's born.
Basic class instantiation techniques
Building on the basic __init__ method, you can add flexibility with default parameters, generate objects in a loop, or use class methods as alternative constructors.
Using constructor parameters with default values
class Rectangle:
def __init__(self, width=0, height=0):
self.width = width
self.height = height
rect1 = Rectangle(10, 5)
rect2 = Rectangle(width=8)
print(f"Rectangle 1: {rect1.width}x{rect1.height}")
print(f"Rectangle 2: {rect2.width}x{rect2.height}")--OUTPUT--Rectangle 1: 10x5
Rectangle 2: 8x0
Setting default values in the __init__ method, like width=0, adds a layer of flexibility to your class. This lets you create instances even when some arguments are missing, making your code more adaptable.
- When you create
rect1, you provide both arguments, which override the defaults. - For
rect2, you only specify thewidth. Theheightparameter isn't provided, so it automatically falls back to its default value of0.
This technique is great for making your classes easier to use, as you only need to supply the values that differ from the standard setup.
Creating multiple instances in a loop
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
points = [Point(i, i*2) for i in range(3)]
for i, point in enumerate(points):
print(f"Point {i}: ({point.x}, {point.y})")--OUTPUT--Point 0: (0, 0)
Point 1: (1, 2)
Point 2: (2, 4)
You can efficiently generate multiple class instances using a list comprehension. This concise syntax is perfect for creating a collection of objects in a single, readable line of code.
- The expression
[Point(i, i*2) for i in range(3)]iterates three times. - In each iteration, it creates a new
Pointobject with coordinates based on the loop variableiand adds it to thepointslist.
This approach is a clean and Pythonic way to populate data structures with custom objects, such as setting up a series of coordinates or initializing a group of game elements.
Using factory methods with @classmethod
class Circle:
def __init__(self, radius):
self.radius = radius
@classmethod
def from_diameter(cls, diameter):
return cls(diameter / 2)
c1 = Circle(5)
c2 = Circle.from_diameter(10)
print(f"Circle 1 radius: {c1.radius}")
print(f"Circle 2 radius: {c2.radius}")--OUTPUT--Circle 1 radius: 5
Circle 2 radius: 5.0
The @classmethod decorator lets you define factory methods, which are alternative ways to create instances of your class. Instead of being tied to a specific instance, these methods operate on the class itself—providing more intuitive entry points for object creation.
- The
from_diametermethod receives the class as its first argument, conventionally namedcls. - It takes a
diameter, calculates the radius, and then callscls(diameter / 2)to create a newCircleinstance using the main constructor. - This approach makes your code more self-explanatory, as you can now create a circle from its diameter directly.
Advanced class instantiation patterns
Moving beyond basic constructors, you can gain finer control with __new__, create instances from varied data formats, or even generate classes dynamically with type().
Customizing object creation with __new__
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
obj1 = Singleton()
obj2 = Singleton()
print(f"Same instance? {obj1 is obj2}")--OUTPUT--Same instance? True
The __new__ method gives you control over the object creation process itself, running before __init__. It’s what actually constructs the instance. This makes it ideal for implementing patterns like the Singleton, which guarantees only one instance of a class is ever created.
- The first time you call
Singleton(),__new__sees that_instanceisNoneand creates a new object. - On any subsequent call, it simply returns the existing object stored in
_instance.
This is why both obj1 and obj2 point to the exact same object, as confirmed by the is operator.
Creating instances from different data formats
class Time:
def __init__(self, hours, minutes):
self.hours = hours
self.minutes = minutes
@classmethod
def from_string(cls, time_str):
h, m = map(int, time_str.split(':'))
return cls(h, m)
t = Time.from_string("16:45")
print(f"Time: {t.hours}:{t.minutes}")--OUTPUT--Time: 16:45
Class methods are perfect for creating instances from different data formats, such as a string or a dictionary. This keeps your main constructor clean while providing intuitive ways to build objects from varied sources.
- The
from_stringmethod acts as a specialized constructor that parses a time string. - It uses
split(':')to separate the hours and minutes, then converts them to integers. - Finally, it calls
cls(h, m)to pass the parsed data to the primary__init__method, creating a newTimeobject.
Dynamic class instantiation with type()
attributes = {'x': 10, 'y': 20, 'get_coords': lambda self: (self.x, self.y)}
DynamicPoint = type('DynamicPoint', (), attributes)
point = DynamicPoint()
print(f"Coordinates: {point.get_coords()}")
print(f"Class name: {point.__class__.__name__}")--OUTPUT--Coordinates: (10, 20)
Class name: DynamicPoint
The type() function offers a powerful way to create classes programmatically, which is perfect for when a class structure isn't known until runtime. It essentially lets you build a class from scratch using code.
- The first argument to
type()is the class name, in this case,'DynamicPoint'. - The second is a tuple of parent classes for inheritance—it's empty here.
- The third is a dictionary,
attributes, that maps names to the class's properties and methods.
Once defined, you can instantiate DynamicPoint just like any regular class, giving you a flexible way to handle dynamic object models.
Move faster with Replit
Replit is an AI-powered development platform that transforms natural language into working applications. Describe what you want to build, and Replit Agent creates it—complete with databases, APIs, and deployment.
For the class instantiation patterns we've explored, Replit Agent can turn them into production-ready tools:
- Build a time zone utility that creates
Timeobjects from string inputs, similar to thefrom_stringfactory method. - Create a simple 2D game that generates a collection of
Pointobjects in a loop to define object positions. - Deploy a system-wide configuration manager that uses the Singleton pattern with
__new__to ensure a single, consistent settings object.
Describe your app idea, and Replit Agent writes the code, tests it, and fixes issues automatically, all in your browser. Start building your next project with Replit Agent.
Common errors and challenges
Even experienced developers can run into a few common pitfalls when instantiating classes, but they're easy to fix once you spot them.
- Forgetting the
selfparameter in methods. A frequent mistake is forgetting theselfparameter in a method definition. Since Python automatically passes the instance as the first argument, leaving outselfresults in aTypeErrorbecause the method receives an argument it wasn't defined to accept. - Unintentionally modifying class variables. Class variables are shared across all instances. If you modify one through an instance, you might accidentally create a new instance variable that "shadows" the class variable for that object only, leading to inconsistent behavior that can be tricky to debug.
- Forgetting to call the parent constructor with
super(). In inheritance, if you define an__init__method in a child class, you must callsuper().__init__(). Failing to do so skips the parent's setup, which often causes anAttributeErrorwhen you try to access inherited attributes.
Forgetting the self parameter in methods
It's a classic mistake: you define a method but forget to include self as the first parameter. Since Python automatically passes the instance to the method, this mismatch leads to a TypeError. The following code demonstrates this common error in action.
class Calculator:
def __init__(self, value):
self.value = value
def add(value_to_add): # Missing self parameter
self.value += value_to_add
return self.value
calc = Calculator(5)
print(calc.add(3)) # Will raise TypeError
When calling calc.add(3), Python passes two arguments: the calc instance and the number 3. Since the add method was only defined to accept one, a TypeError occurs. The corrected implementation resolves this.
class Calculator:
def __init__(self, value):
self.value = value
def add(self, value_to_add): # Added self parameter
self.value += value_to_add
return self.value
calc = Calculator(5)
print(calc.add(3)) # Outputs: 8
The fix is simple but crucial: adding self as the first parameter to the add method. When you call calc.add(3), Python automatically sends the calc instance as the first argument. The corrected method signature, def add(self, value_to_add):, is now equipped to receive both the instance and the number 3. This allows the method to correctly access and modify the instance's value attribute, resolving the original TypeError.
Unintentionally modifying class variables
It's a common mix-up: you define a class variable like items, expecting it to be unique for each instance, but it's actually shared. When this variable is a mutable type like a list, modifying it through one object affects all others. The following code demonstrates this.
class ShoppingCart:
items = [] # Class variable shared across all instances
def __init__(self, customer_id):
self.customer_id = customer_id
def add_item(self, item):
self.items.append(item)
cart1 = ShoppingCart("user1")
cart1.add_item("apple")
cart2 = ShoppingCart("user2")
cart2.add_item("banana")
print(cart1.items) # Contains both items: ['apple', 'banana']
Since items is a class variable, both cart1 and cart2 append to the same list. This is why cart1’s cart unexpectedly contains items from cart2. The corrected implementation below resolves this issue.
class ShoppingCart:
def __init__(self, customer_id):
self.customer_id = customer_id
self.items = [] # Instance variable unique to each instance
def add_item(self, item):
self.items.append(item)
cart1 = ShoppingCart("user1")
cart1.add_item("apple")
cart2 = ShoppingCart("user2")
cart2.add_item("banana")
print(cart1.items) # Contains only: ['apple']
The solution is to move the list initialization into the __init__ method. By defining self.items = [] within the constructor, you ensure that each ShoppingCart instance gets its own unique list. This makes items an instance variable rather than a shared class variable. As a result, adding an item to one cart no longer affects any others. Always watch for this when using mutable types like lists or dictionaries as class attributes.
Forgetting to call the parent constructor with super()
When a child class defines its own __init__ method, it overrides the parent's constructor. If you don't call super().__init__(), the parent's initialization logic never runs, leaving inherited attributes undefined and often causing an AttributeError. The following code demonstrates this common oversight.
class Animal:
def __init__(self, species):
self.species = species
class Dog(Animal):
def __init__(self, name, breed):
self.name = name
self.breed = breed
dog = Dog("Rex", "Labrador")
print(dog.species) # AttributeError: 'Dog' has no attribute 'species'
The Dog class's __init__ method completely replaces the parent's constructor, so the species attribute is never assigned. The corrected implementation below shows how to properly initialize both the child and parent classes.
class Animal:
def __init__(self, species):
self.species = species
class Dog(Animal):
def __init__(self, name, breed):
super().__init__("Canine")
self.name = name
self.breed = breed
dog = Dog("Rex", "Labrador")
print(dog.species) # Outputs: Canine
By calling super().__init__("Canine") inside the Dog class's __init__ method, you ensure the parent Animal constructor runs. This is what sets the species attribute. When you define an __init__ in a child class, it overrides the parent's, so you must explicitly call super() to run both. This simple step connects the inheritance chain, preventing an AttributeError when you try to access attributes that should have been inherited.
Real-world applications
Putting these patterns into practice, you can build tools like a user profile loader with a from_database() method or a callable converter using __call__().
Building user profiles with from_database() method
A factory method like from_database() provides an intuitive way to create an instance by parsing data directly from a source, such as a database record.
class UserProfile:
def __init__(self, username, email):
self.username = username
self.email = email
@classmethod
def from_database(cls, data):
return cls(data['username'], data['email'])
db_data = {'username': 'john_doe', 'email': '[email protected]'}
user = UserProfile.from_database(db_data)
print(f"Created user: {user.username}, {user.email}")
The from_database method offers a specialized way to create UserProfile objects. Because it's a @classmethod, it receives the class (cls) directly, allowing it to act as an alternative constructor.
- It takes a dictionary, like one you might get from a database query.
- It then unpacks the data and calls the primary
__init__method viacls().
This approach neatly separates the task of data parsing from the core object setup. It keeps your __init__ constructor simple and focused on just assigning attributes.
Building a temperature converter with __call__
The __call__ method lets you create objects that behave like functions, which is ideal for building stateful tools that perform a specific action when called.
class TemperatureConverter:
def __init__(self, from_unit):
self.from_unit = from_unit
def __call__(self, value):
if self.from_unit == "C":
return value * 9/5 + 32
return (value - 32) * 5/9
celsius_to_f = TemperatureConverter("C")
print(f"25°C = {celsius_to_f(25):.1f}°F")
print(f"30°C = {celsius_to_f(30):.1f}°F")
The TemperatureConverter class is initialized with a unit like "C", which it stores as an instance variable. This makes the object, celsius_to_f, a specialized converter that remembers its state.
- By defining the
__call__method, you make the object callable, so it behaves like a function. - When you run
celsius_to_f(25), Python invokes the__call__method on that specific instance. - The method then uses the stored unit to apply the correct conversion formula, returning the result.
Get started with Replit
Turn these patterns into a real tool. Tell Replit Agent: “Build a temperature converter app using a callable class” or “Create a user profile system that instantiates objects from a dictionary.”
Replit Agent writes the code, tests for errors, and deploys your application for you. Start building with Replit.
Create and deploy websites, automations, internal tools, data pipelines and more in any programming language without setup, downloads or extra tools. All in a single cloud workspace with AI built in.
Create & deploy websites, automations, internal tools, data pipelines and more in any programming language without setup, downloads or extra tools. All in a single cloud workspace with AI built in.


.png)
.png)