OOP in Python

Python OOP is lighter than C# — fewer keywords, more conventions. Six ideas, no fluff.

▶ Watch this reel

What you'll learn

  1. Classes & __init__
  2. Dunder methods
  3. Inheritance & super()
  4. dataclasses
  5. Protocol & ABC
  6. @property

Remember this

Classes & __init__

class Model:
    def __init__(self, name: str, price: float = 0.0):
        self.name = name          # attribute created by assignment
        self.price = price

Dunder methods

DunderEnables
__init__construction
__len__len(obj)
__str__ / __repr__print / REPL debug
__eq__==
__getitem__obj[i]

Inheritance & super()

dataclasses

@dataclass(frozen=True)
class Model:
    name: str
    tags: list = field(default_factory=list)

= records: __init__ + __eq__ + __repr__ generated.

Protocol & ABC

@property

Code: OOP the Python way — 30 lines, everything from this reel

from dataclasses import dataclass, field
from typing import Protocol
import functools

# --- dataclass: the record you'll write most ------------------
@dataclass(frozen=True)
class Model:
    name: str
    input_price: float          # per 1M tokens, USD

    @property
    def cost_usd(self, tokens: int = 1_000_000) -> float:
        return self.input_price * tokens / 1_000_000

# --- Protocol: structural interface (no inheritance!) ---------
class Storage(Protocol):
    def save(self, key: str, value: dict) -> None: ...
    def load(self, key: str) -> dict | None: ...

class MemoryStore:               # satisfies Storage automatically
    def __init__(self): self._data = {}
    def save(self, key, value): self._data[key] = value
    def load(self, key): return self._data.get(key)

def persist(store: Storage):     # mypy checks the SHAPE, not the parent
    store.save("config", {"model": "gpt-4o"})

# --- classic class with dunders -------------------------------
class Pipeline:
    def __init__(self, steps: list | None = None):
        self.steps = steps if steps is not None else []

    def __len__(self): return len(self.steps)
    def __str__(self): return f"Pipeline({len(self.steps)} steps)"

    def add(self, step): self.steps.append(step); return self

p = Pipeline().add("embed").add("search")
print(len(p), str(p))