Learning LibraryCore Coding LibraryTeens

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

1The basics

__init__ runs automatically when an object is created. self is the object being built, and self.name = name stores a value on it:

python
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)
Run it. One class, one object:
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.

2A step further

Every object keeps its own attributes. Changing one product leaves the others untouched:

python
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)
Run it. Two objects, independent data:
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.

3At Evergreen

Add a method and each object can compute its own figures. A list of objects then becomes a catalog you can loop over:

python
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")
Run it. Every product reports its margin:
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.

The same idea, everywhere

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.