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.
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.
Practice this lesson
12 questions with immediate explanations.