← Master Index
Vol. 03 Module 3.2 Lecture

Classes

Object-Oriented Programming

How This Lesson Fits the Module

Module 3.1 gave you Python building blocks: variables, lists, functions, and loops. Real ML projects quickly outgrow loose scripts—a training pipeline needs datasets, models, optimizers, loggers, and evaluators that share structure but hold different data.

Classes are Python’s blueprint for that structure. A class defines what attributes (data) and methods (behavior) every instance of a concept will have. PyTorch’s Dataset, scikit-learn’s BaseEstimator, and your own ImageClassifier all start as class definitions.

This is the first step toward organizing ML code the way production frameworks do.

Learning Objectives

By the end of this lesson, students should be able to:

  • Define a Python class with class, __init__, instance attributes, and instance methods.
  • Distinguish between a class (blueprint) and an object (instance created from that blueprint).
  • Explain why ML libraries expose concepts like datasets and models as classes rather than loose functions.
  • Write a simple ModelConfig or TabularDataset class that bundles related training settings or data.
  • Read third-party ML class definitions and identify attributes, methods, and constructor parameters.
  • Recognize class-level patterns used in PyTorch (nn.Module) and scikit-learn estimators.

Introduction: From Scripts to Blueprints

Imagine a training script with scattered global variables:

learning_rate = 0.001
batch_size = 64
epochs = 10
model_name = "resnet18"
features = [...]
labels = [...]

It works for a notebook experiment, but scaling to multiple experiments, team collaboration, or unit tests becomes painful. Related data and behavior belong together. A class groups them under one name.

In machine learning, classes model recurring entities: a dataset knows how to load and return samples; a model knows how to forward-pass inputs; a trainer knows how to loop over batches. Frameworks ship hundreds of pre-built classes—understanding how to define your own is essential.

Defining a Class

Definition — Class

A class is a user-defined type that describes the structure and behavior of objects. It declares attributes (data each instance stores) and methods (functions that operate on instance data). Objects are created by instantiating the class.

Minimal syntax:

class ModelConfig:
    """Holds hyperparameters for a training run."""

    def __init__(self, learning_rate, batch_size, epochs):
        self.learning_rate = learning_rate
        self.batch_size = batch_size
        self.epochs = epochs

    def summary(self):
        return (
            f"lr={self.learning_rate}, "
            f"batch={self.batch_size}, epochs={self.epochs}"
        )
Element Role in ML Code
class ModelConfig Blueprint for all training configurations; name should describe the concept clearly.
__init__ Constructor—runs when you create an instance; sets initial attribute values.
self Reference to the current instance; required as the first parameter of instance methods.
self.learning_rate Instance attribute—each ModelConfig object has its own copy.
summary() Instance method—behavior tied to the object’s data (e.g., logging config to W&B).

ML Example: A Tabular Dataset Class

Before PyTorch’s torch.utils.data.Dataset, understand the pattern in plain Python. A dataset class wraps features and labels and exposes a consistent interface:

class TabularDataset:
    """In-memory dataset for tabular ML (features + labels)."""

    def __init__(self, features, labels):
        if len(features) != len(labels):
            raise ValueError("features and labels must have same length")
        self.features = features
        self.labels = labels

    def __len__(self):
        return len(self.features)

    def __getitem__(self, index):
        return self.features[index], self.labels[index]

    def num_features(self):
        return len(self.features[0]) if self.features else 0

Usage:

features = [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]
labels = [0, 1, 0]

dataset = TabularDataset(features, labels)
print(len(dataset))           # 3
x, y = dataset[1]             # ([3.0, 4.0], 1)
print(dataset.num_features()) # 2

This mirrors what every deep learning Dataset must provide: length, indexed access, and metadata. PyTorch’s DataLoader expects exactly these dunder methods (__len__, __getitem__).

Class vs. Instance

Class

The template defined once in code. TabularDataset describes how any tabular dataset behaves.

Instance (Object)

A concrete object created from the class. train_ds and val_ds are separate instances with different feature/label data.

Why It Matters in ML

You define ImageDataset once, then instantiate train_set, val_set, and test_set—same interface, different data.

train_ds = TabularDataset(train_features, train_labels)
val_ds = TabularDataset(val_features, val_labels)

# Same class, different objects, independent state
assert train_ds is not val_ds
assert len(train_ds) != len(val_ds)  # typically

How Frameworks Use Classes

Every major ML library is built on classes:

Reading Framework Code

When you write model = nn.Linear(784, 10), you are instantiating the Linear class. The constructor stores weight and bias tensors as instance attributes. Calling model(x) invokes Linear.forward()—an instance method. The class defines the architecture; the instance holds the trained parameters.

Class Attributes vs. Instance Attributes

Attributes defined directly on the class (outside __init__) are shared by all instances. Instance attributes (assigned via self. in __init__) are per-object.

class ExperimentLogger:
  task_type = "classification"  # class attribute (shared default)

  def __init__(self, run_name):
      self.run_name = run_name    # instance attribute (per experiment)
      self.metrics = {}           # each logger tracks its own metrics

For ML code, prefer instance attributes for data that varies per object (weights, datasets, hyperparameters). Use class attributes sparingly—for constants like default image size or task type.

Common Misconceptions

Misconception 1: “Classes are only for large programs.”

Reality: Even a 50-line notebook benefits from a Config or Dataset class. Grouping related state prevents bugs from mutable global variables.

Misconception 2:self is a Python keyword.”

Reality: self is a naming convention. You could use another name, but every ML codebase uses self—follow the convention.

Misconception 3: “I should rewrite PyTorch modules from scratch.”

Reality: Subclass nn.Module and compose existing layers. Classes help you organize and extend frameworks, not replace them.

Quick Knowledge Check

  1. Short Answer: What method initializes a new object? Answer: __init__.
  2. True/False: Two instances of the same class always share the same attribute values. Answer: False—instance attributes are independent unless they reference shared mutable objects.
  3. Short Answer: Why do PyTorch datasets implement __len__ and __getitem__? Answer: So DataLoader can batch and shuffle samples by index.
  4. Multiple Choice: self in a method refers to: (a) the class, (b) the current instance, (c) the parent class, (d) the module. Answer: (b).
  5. Short Answer: Name two ML library concepts that are typically classes. Answer: e.g., Dataset, Model/Estimator, DataLoader, Optimizer.
  6. Short Answer: What is the difference between a class and an object? Answer: A class is the blueprint; an object is a concrete instance created from it.
  7. True/False: self is a Python keyword that cannot be renamed. Answer: False—it is a convention, not a keyword.
  8. Multiple Choice: ModelConfig.__init__ mainly: (a) trains the model, (b) sets instance attributes, (c) imports NumPy, (d) freezes weights. Answer: (b).
  9. Short Answer: Why group hyperparameters in a class instead of globals? Answer: Related state stays together, reducing bugs from mutable global variables and easing experiments.
  10. True/False: scikit-learn estimators such as LogisticRegression are classes with fit and predict. Answer: True.

Key Takeaways

  • A class is a blueprint; an object is a concrete instance created from it.
  • __init__ sets up instance attributes; methods define behavior using self.
  • ML code uses classes to bundle data and operations: configs, datasets, models, trainers.
  • Dataset classes expose __len__ and __getitem__—the contract DataLoader expects.
  • Frameworks like PyTorch and scikit-learn are class hierarchies; you extend them by defining your own classes.
Trainer’s Guide

Hands-on: Have students refactor a script with global lr, batch_size, and epochs into a ModelConfig class. Print config.summary() before training.

Bridge: The next lecture, Objects, explores what happens after instantiation—identity, state, and how objects interact in a training pipeline.

What’s Next Continue to Objects to learn how instances carry state, how they are passed through ML pipelines, and why mutability matters for tensors and datasets.