Lesson 15 · Beginner · 19 min

Python Classes and Objects

Group data and the functions that work on it into a small, reusable object.

class definition__init__ and selfmethods and instances

Every order carries a drink, a size, and a price, and three functions keep passing them around separately. A class lets one object carry them together. What should that object be able to do for itself?

A class is a blueprint for objects. An object stores data in attributes and exposes behaviour through methods. Start with a small record such as an order, then add one method at a time. You will also separate shared class state from per-object state, enforce invariants in __init__, and add a useful repr.

Define a class

The class keyword creates a blueprint. __init__ runs when a new object is created. self refers to that specific object, and attributes are assigned with self.name.

class Order:
    def __init__(self, drink, price):
        self.drink = drink
        self.price = price

order = Order("latte", 4.5)
print(order.drink)
print(order.price)

A small class

Add a method

A method is a function defined inside a class. Its first parameter is self. Use it to read the object's attributes and return a result; callers do not pass self explicitly.

class Order:
    def __init__(self, drink, price, quantity=1):
        self.drink = drink
        self.price = price
        self.quantity = quantity

    def total(self):
        return self.price * self.quantity

print(Order("latte", 4.5, 2).total())

A method with a default

Create independent objects

Each instance has its own attribute values. A loop over a list of objects is often clearer than several parallel lists. Print one field at a time to inspect what each object holds.

class Order:
    def __init__(self, drink, price):
        self.drink = drink
        self.price = price

orders = [Order("latte", 4.5), Order("tea", 3.0)]
for order in orders:
    print(order.drink, order.price)

A list of objects

Class attributes are shared

An attribute assigned in the class body belongs to the class, not to each object. A mutable class attribute is shared by every instance. Put per-object defaults in __init__; keep a value on the class only when every instance should share it.

class Order:
    tags = []

    def __init__(self, drink):
        self.drink = drink

first = Order("latte")
second = Order("tea")
first.tags.append("gift")
print(second.tags)
print(first.tags is second.tags)

One list shared by every order

Validate invariants when the object is created

An object should not exist in an invalid state. Check price and quantity in __init__ and raise ValueError with the bad value. Callers then handle one clear failure instead of discovering a negative total much later.

class Order:
    def __init__(self, drink, price):
        if price < 0:
            raise ValueError(f"negative price: {price}")
        self.drink = drink
        self.price = price

for price in [4.5, -1]:
    try:
        order = Order("latte", price)
        print(order.drink, order.price)
    except ValueError as error:
        print(type(error).__name__, error)

Reject the object before it exists

A repr should help you debug

print(order) falls back to __repr__ when __str__ is absent. A good __repr__ shows the class and the fields that identify the object. It is for developers, so keep it unambiguous instead of writing a friendly sentence.

class Order:
    def __init__(self, drink, price, quantity=1):
        self.drink = drink
        self.price = price
        self.quantity = quantity

    def __repr__(self):
        return f"Order(drink={self.drink!r}, price={self.price}, quantity={self.quantity})"

print(Order("latte", 4.5, 2))

Show the class and its identifying fields

Key points

  • A class defines the shape of an object.
  • __init__ initialises a new instance.
  • self refers to the current instance.
  • Methods can read attributes and return computed values.
  • Mutable defaults belong in __init__; class attributes are shared.

Common mistakes

  • Forgetting self in the method definition.
  • Creating a class but never calling it to make an object.
  • Sharing one mutable attribute across instances by accident.
  • Using a class-level list as a per-object tag list.
Your turn

Create an Order class with drink and price, then print a formatted total for two orders.

Try it yourself

Change the values, predict the output, then run the code. The Python runtime is downloaded the first time you press Run, so the first run can take a few seconds.

In-browser PythonRuns locally · no account
First run downloads Pyodide from a CDN. Use Run code after editing.

Practice this lesson

12 questions with immediate explanations.

See all 12 answersStart practice
← sorting and keysmodules →