Classes and Objects

Bundle data and behaviour into your own types

Intermediate 11 min

In this lesson

In Python, a class is a blueprint for your own kind of thing, and an object is one specific thing built from that blueprint — bundling related data together with the actions that belong to it. You already group values with dictionaries and reuse logic with functions; a class brings those two ideas together. By the end you’ll define a class, make objects from it, and see why that’s often clearer than loose dictionaries.

Explain it like I’m 5

A class is a recipe; an object is the cookie you bake from it. You write the recipe once, then bake as many cookies as you like — and each cookie is its own separate cookie.

From a loose dictionary to a class

Suppose you’re tracking pets. With a dictionary you’d write one dict per pet and reach in by key. That works, but nothing stops a typo like pet["naem"], and any behaviour — say, ‘describe this pet’ — lives in separate functions far from the data.

A class is a blueprint for a new type. It says what every pet has (its data) and what every pet can do (its methods), all in one place. From that one blueprint you create objects (also called instances): individual pets, each with its own values.

Example
# One pet as a dictionary
pet = {"name": "Rex", "species": "dog", "age": 3}
print(pet["name"], "is a", pet["age"], "year old", pet["species"])
Output
Rex is a 3 year old dog
A dictionary works, but the data and any behaviour stay separate.
Example
class Pet:
    def __init__(self, name, species, age):
        self.name = name
        self.species = species
        self.age = age

rex = Pet("Rex", "dog", 3)
print(rex.name, "is a", rex.age, "year old", rex.species)
Output
Rex is a 3 year old dog
The same pet as an object made from a Pet class.

__init__ and self, decoded

Two bits of class syntax trip up newcomers. __init__ is the setup method Python runs automatically every time you create an object — it’s where the new object gets its starting attributes. self simply means ‘this particular object’: when you write self.name = name, you’re saying ‘store this name on the object being built right now’.

You never pass self yourself — Python fills it in. Pet("Rex", "dog", 3) calls __init__ with self set to the brand-new pet and the three values lined up after it.

Methods: behaviour that lives with the data

A method is just a function defined inside a class. Because its first parameter is self, it can read and change that object’s attributes. This is the real payoff of classes: the action that belongs to a pet lives right next to the pet’s data.

Example
class Pet:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def describe(self):
        return f"{self.name} is {self.age} years old"

rex = Pet("Rex", 3)
print(rex.describe())
Output
Rex is 3 years old
describe() reads the object's own attributes through self.

Add a birthday() method that adds one year to the pet's age. Call it once, then print the pet's age.

class Pet:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def birthday(self):
        pass  # TODO: add one year to self.age

rex = Pet("Rex", 3)
rex.birthday()
print(rex.age)

Common mistake: Forgetting self in a method definition

Why it happens:

Methods look like ordinary functions, so it’s easy to write def describe(): and leave out the self parameter.

How to fix it:

Every regular method needs self as its first parameter. Without it, calling rex.describe() raises a TypeError about an unexpected argument, because Python still passes the object in.

Common mistake: Calling a method without parentheses

Why it happens:

rex.describe looks like it should run, but without () you get the method object itself, not its result.

How to fix it:

Add the parentheses: rex.describe(). The empty parentheses are how you actually call it.

Common mistake: Confusing the class with the object

Why it happens:

The class and the things made from it feel like the same idea at first.

How to fix it:

The class (Pet) is the blueprint; the object (rex) is one thing built from it. You can make many objects from one class, and each keeps its own attribute values.

Which line creates an object from the Pet class?

Inside a method, what does self.name refer to?

Why can two pets made from the same class have different names?

Mini exercise (medium)

Define a Pet class with name, species, and age attributes and a describe() method that returns a sentence like "Rex is a 3-year-old dog". Create two pets and print each one’s description.

Do it here. Finish the code below and press Run to try your answer right in the browser — no setup needed.

class Pet:
    def __init__(self, name, species, age):
        # TODO: store name, species and age on self
        pass

    def describe(self):
        # TODO: return e.g. "Rex is a 3-year-old dog"
        return ""

rex = Pet("Rex", "dog", 3)
mia = Pet("Mia", "cat", 2)
print(rex.describe())
print(mia.describe())

What to learn next

You learned what a class and an object really are: a class is the blueprint, and each object built from it carries its own attributes. You saw how __init__ sets a new object up, how self means ‘this particular object’, and how methods keep behaviour next to the data. You built a Pet class and gave two pets their own descriptions.

Next we go deeper into what objects hold and how that changes over time. Attributes, Methods, and Object State shows how methods read and safely update an object’s state, and why returning a value usually beats printing inside a method. When you’re ready, continue to the next lesson.