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.

How to create an instance of a class in Python
Published on: 
Tue
Mar 10, 2026
Updated on: 
Fri
Mar 13, 2026
The Replit Team

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 (as self) and the argument "Alice".
  • It then assigns this value to the instance's name attribute, 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 the width. The height parameter isn't provided, so it automatically falls back to its default value of 0.

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 Point object with coordinates based on the loop variable i and adds it to the points list.

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_diameter method receives the class as its first argument, conventionally named cls.
  • It takes a diameter, calculates the radius, and then calls cls(diameter / 2) to create a new Circle instance 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 _instance is None and 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_string method 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 new Time object.

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 Time objects from string inputs, similar to the from_string factory method.
  • Create a simple 2D game that generates a collection of Point objects 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 self parameter in methods. A frequent mistake is forgetting the self parameter in a method definition. Since Python automatically passes the instance as the first argument, leaving out self results in a TypeError because 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 call super().__init__(). Failing to do so skips the parent's setup, which often causes an AttributeError when 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 via cls().

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.

Get started free

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.

Get started for free

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.