How to Create an Object in Python

What you’ll build or solve

You’ll create objects in Python using classes, constructors, and methods.

When this approach works best

Creating an object works best when you:

  • Group related data and behavior together, like a User with email and display_name().
  • Track state that changes over time, like a Timer that can start, stop, and report elapsed time.
  • Create many similar things, like Product objects built from rows in a file or API response.

Avoid this approach when a simple dictionary is enough and you do not need behavior. For a small one-off structure, a dict can stay clearer.

Prerequisites

  • Python installed
  • You know what a function is
  • You know what a dictionary is

Step-by-step instructions

1) Define a class and instantiate it

Define a class, then call it like a function to create an instance.

classUser:
pass

u1=User()
u2=User()

print(type(u1))
print(u1isu2)

What to look for:

User() constructs a new object each time you call it. In Python, every value, including strings, numbers, and lists, is already an object.


2) Use __init__ to set attributes

Use __init__ to set up the object’s attributes right when you create it.

classUser:
def__init__(self,email):
self.email=email
self.is_active=True

u=User("mina@example.com")
print(u.email,u.is_active)

What to look for:

self refers to the current instance. Assigning self.email = ... creates an attribute on that object.


3) Add methods that use the object’s data

Methods let your object do useful work with its own state.

classUser:
def__init__(self,email):
self.email=email

defdisplay_name(self):
returnself.email.split("@")[0]

u=User("lea@example.com")
print(u.display_name())

Option A: Update internal state from a method

classCounter:
def__init__(self,start=0):
self.value=start

definc(self):
self.value+=1

c=Counter(10)
c.inc()
c.inc()
print(c.value)

What to look for:

Call methods on an instance, like u.display_name(), not on the class itself.


Examples you can copy

Example 1: Create multiple objects from a list of dictionaries

classTask:
def__init__(self,title,done=False):
self.title=title
self.done=done

rows= [
    {"title":"buy milk","done":True},
    {"title":"send email","done":False},
    {"title":"workout","done":False},
]

tasks= [Task(row["title"],row["done"])forrowinrows]

print(tasks[0].title,tasks[0].done)
print(len(tasks))

Example 2: Validate inputs during object creation

classDiscount:
def__init__(self,percent):
ifnot (0<=percent<=100):
raiseValueError("percent must be between 0 and 100")
self.percent=percent

d=Discount(15)
print(d.percent)

Example 3: Use a class method as an alternate constructor

This pattern helps when you want to create an object from a different input shape.

classUser:
def__init__(self,email):
self.email=email

@classmethod
deffrom_username(cls,username,domain="example.com"):
returncls(f"{username}@{domain}")

u=User.from_username("mila",domain="mimo.org")
print(u.email)

Example 4: Store computed values on the object

classRectangle:
def__init__(self,width,height):
self.width=width
self.height=height
self.area=width*height

r=Rectangle(3,5)
print(r.area)

Example 5: Build objects from an API-like response

classProduct:
def__init__(self,name,price):
self.name=name
self.price=price

response_items= [
    {"name":"Notebook","price":12},
    {"name":"Pen","price":2},
]

products= [Product(item["name"],item["price"])foriteminresponse_items]
print(products[0].name,products[0].price)

Example 6: Use @dataclass for data-focused objects with less boilerplate

This is handy when you mostly store data and want a shorter class definition.

fromdataclassesimportdataclass

@dataclass
classProduct:
name:str
price:int

p=Product("Notebook",12)
print(p)
print(p.name,p.price)

Common mistakes and how to fix them

Mistake 1: Forgetting to use self when setting attributes

What you might do

classUser:
def__init__(self,email):
email=email# does nothing useful

Why it breaks

You assign to a local variable, not to the object. The instance never gets an email attribute.

Fix

classUser:
def__init__(self,email):
self.email=email

u=User("mina@example.com")
print(u.email)

Mistake 2: Using a mutable default value in __init__

What you might do

classBag:
def__init__(self,items=[]):
self.items=items

Why it breaks

That list is shared across instances. Changes leak between objects.

Fix

classBag:
def__init__(self,items=None):
self.items= []ifitemsisNoneelselist(items)

a=Bag()
b=Bag()
a.items.append("key")

print(a.items)
print(b.items)

Mistake 3: Treating a class like an instance

What you might do

classUser:
def__init__(self,email):
self.email=email

print(User.email)

Why it breaks

email exists on instances, not on the class itself.

Fix

u=User("ivan@example.com")
print(u.email)

Troubleshooting

If you see TypeError: __init__() missing ..., you called User() without the required arguments. Pass the values your constructor expects.

If you see AttributeError: 'User' object has no attribute 'email', you never set self.email in __init__, or you misspelled the attribute name.

If you see TypeError: 'User' object is not callable, you tried to call an instance like u(). Call the class to create objects, like User().

If your objects share list data by accident, check for mutable defaults like [] or {} in __init__ and switch to None.

If the @dataclass example errors, confirm you are on Python 3.7+ and that fields with defaults come after fields without defaults.


Quick recap

  • Define a class, then create an instance with ClassName().
  • Use __init__ to set attributes on self.
  • Add methods to act on the object’s data and state.
  • Avoid mutable default arguments like items=[].
  • Use @dataclass when you want a shorter data-focused class.