Up to now we’ve put data in variables and operations in functions. Object-oriented programming (OOP) bundles them together. A class describes a kind of thing; an object is one specific instance of that thing.

Almost everything in Python is already an object — lists, strings, files, even numbers. This section is about building your own.

A first class

class User:
    pass

class User: defines a new class called User. The body is pass for now — an empty placeholder.

To create an instance, call the class like a function:

u1 = User()
u2 = User()

print(u1)        # <__main__.User object at 0x...>
print(u2)        # <__main__.User object at 0x...>
print(u1 is u2)  # False — two separate objects

Each call to User() creates a fresh object.

Class vs object — analogy

Think of a class as a blueprint and an object as a building. The blueprint says “every house has rooms, doors, windows”. Each actual house — built from the blueprint — has its own rooms, doors, windows.

In Python:

  • User is the class (the blueprint).
  • u1 = User() creates one object (one specific user).
  • u2 = User() creates another, completely independent.

Adding attributes

You can attach data — called attributes — to an object:

u1 = User()
u1.name = "Manikandan"
u1.age = 30

print(u1.name)   # 'Manikandan'
print(u1.age)    # 30

But this is a poor design. Every user has to be set up manually, and one might forget a field. We want every User to start with its core data — that’s what a constructor is for.

A proper class

class User:
    def __init__(self, name: str, age: int) -> None:
        self.name = name
        self.age = age


u1 = User("Manikandan", 30)
u2 = User("Alice", 25)

print(u1.name, u1.age)   # Manikandan 30
print(u2.name, u2.age)   # Alice 25

A few things to unpack:

  • __init__ is a special method called automatically when you create an object. It’s the constructor.
  • The first parameter is always self — the object being created. You don’t pass it; Python supplies it.
  • Inside __init__, we set self.name = name to store the name as an attribute of this specific object.

u1 and u2 are now completely independent — each has its own name and age.

self — the object itself

Every method takes self as its first parameter. self is the object the method is being called on:

class User:
    def __init__(self, name: str, age: int) -> None:
        self.name = name
        self.age = age

    def greet(self) -> str:
        return f"Hello, I'm {self.name}"


u = User("Manikandan", 30)
print(u.greet())   # 'Hello, I'm Manikandan'

When you write u.greet(), Python translates it to User.greet(u)self is u. You never pass self yourself; Python does.

Type hints for self

You don’t have to annotate self. Pyright knows it’s the class type.

class User:
    def __init__(self, name: str) -> None:    # no annotation for self
        self.name = name

What can go inside a class?

  • __init__ — the constructor
  • Other methods — functions that operate on the object
  • Class attributes — values shared across all instances (rare, but useful)
  • Properties — controlled attribute access (lesson 4)
class Counter:
    def __init__(self) -> None:
        self.count: int = 0

    def increment(self) -> None:
        self.count += 1

    def reset(self) -> None:
        self.count = 0


c = Counter()
c.increment()
c.increment()
c.increment()
print(c.count)   # 3
c.reset()
print(c.count)   # 0

Each method changes the state of self. The object remembers — that’s the difference between OOP and plain functions.

Why use classes?

Three reasons:

  1. Group related data and behaviour. A User knows their own name and how to greet — instead of passing the name around as an argument to a standalone function.
  2. Reuse and inheritance. One class can be built on top of another (lesson 5).
  3. Models in code. Real-world things (a user, a file, a model, a request) often map naturally to classes.

That said — don’t reach for classes when a function or dict will do. Many small Python programs need no classes at all.

What’s next

You’ve made objects with attributes and methods. Next, a closer look at constructors and attributes — including class attributes and the difference between them.

Toggle theme (T)