Classes and objects in Python: data that carries its own math
A product has a name, a price, a cost, and stock. Four parallel lists can hold that, until someone sorts one of them. A class keeps each product's data together, as one thing.
The big idea
A class is a blueprint; each object created from it holds its own data (attributes) and shares the class's functions (methods).
See it in code
__init__ runs automatically when an object is created. self is the object being built, and self.name = name stores a value on it:
class Product:
def __init__(self, name, price, cost):
self.name = name
self.price = price
self.cost = cost
tee = Product("Organic tee", 38, 14)
print(tee.name, "sells for", tee.price)Organic tee sells for 38
Product(...) built a new object and passed your three arguments to __init__. Dot notation reads the attributes back: tee.name, tee.price.
Every object keeps its own attributes. Changing one product leaves the others untouched:
class Product:
def __init__(self, name, price, cost):
self.name = name
self.price = price
self.cost = cost
tee = Product("Organic tee", 38, 14)
pants = Product("Everyday pants", 78, 29)
tee.price = 42
print(tee.name, tee.price)
print(pants.name, pants.price)Organic tee 42 Everyday pants 78
The tee's price rose to 42; the pants stayed at 78. They share a blueprint, not their data.
Add a method and each object can compute its own figures. A list of objects then becomes a catalog you can loop over:
class Product:
def __init__(self, name, price, cost, stock=0):
self.name = name
self.price = price
self.cost = cost
self.stock = stock
def margin(self):
return (self.price - self.cost) / self.price
catalog = [
Product("Organic tee", 38, 14, stock=12),
Product("Everyday pants", 78, 29, stock=40),
Product("Sage hoodie", 64, 24, stock=25),
]
for item in catalog:
print(f"{item.name}: {item.margin():.1%} margin, {item.stock} in stock")Organic tee: 63.2% margin, 12 in stock Everyday pants: 62.8% margin, 40 in stock Sage hoodie: 62.5% margin, 25 in stock
item.margin() uses that item's own price and cost through self. The loop doesn't need to know how margin is calculated; it just asks each product.
Objects model anything with both state and behavior: a block in a chain, a bank account, a DNA sequence with its own transcribe(), a button on a page.
Try it yourself
Add a Product("Wool socks", 14, 4, stock=60) to the catalog and re-run. Then give the class a profit() method that returns self.price - self.cost.
The common mistake
Leaving self out of a method's parameters. def margin(): raises TypeError: margin() takes 0 positional arguments but 1 was given when called, because Python passes the object in automatically.
What it unlocks
Go deeper on what objects know and do in methods and attributes. Classes build directly on functions and on the lookup idea behind dictionaries.