What you'll learn
Quick Answer
A notebook runs cells in whatever order you click them, not top to bottom, so the visible code may not match the state in memory. Restart and run all before trusting or sharing a result.
What a notebook actually is
A notebook is a document of cells — code, or markdown text — attached to a live Python process called the kernel. Running a cell sends it to the kernel and shows the result underneath.
pip install notebook
jupyter notebook
The value is immediate feedback with the output kept alongside the code. Load a dataset once, then explore it across twenty cells without reloading each time. For data work that loop is genuinely transformative, which is why notebooks took over data science.
Keyboard basics that save a lot of clicking: Shift+Enter runs a cell and moves on, Esc then M turns a cell into markdown, Esc then Y turns it back to code, and Esc then D D deletes a cell.
The hidden state problem
This is the one thing to understand, and it causes most notebook disasters.
Cells run in the order you click them. The kernel remembers everything defined so far, regardless of where it appeared in the document. So this is entirely possible:
- You define
dfin cell 5 and use it in cell 3. - You delete cell 5 — but
dfis still in memory, so cell 3 keeps working. - You share the notebook. It fails immediately for everyone else.
The numbers in the brackets beside each cell show actual execution order. If they read 1, 7, 3, 12, the document is not a program — it is a transcript of a session, and running it top to bottom may produce something different from what you see.
The fix is a habit: Restart Kernel and Run All before trusting a result. Do this before submitting, before sharing, and before drawing any conclusion. If it fails, it was already broken and you simply had not noticed.
Writing a notebook someone else can read
A notebook is a document, so treat it like one:
- Start with a markdown cell saying what the notebook does and what data it needs.
- Put all imports in the first code cell. Scattered imports break the moment someone runs from the top.
- Use markdown headings between sections, so the structure is visible without reading the code.
- Keep cells small. One idea per cell. A forty-line cell defeats the point of the format.
- Delete exploratory dead ends before sharing. The value is the path, not every wrong turn.
Write down conclusions in markdown as you reach them. A chart with no sentence explaining what it shows leaves the reader — including future you — to re-derive the finding.
Notebooks and git do not get along
A .ipynb file is JSON containing the code, the outputs, and execution metadata. So committing one produces a diff full of base64 image data and changed execution counts even when the code is identical.
Practical mitigations: clear all outputs before committing (Cell → All Output → Clear), which removes most of the noise; or use a tool such as nbstripout to do it automatically on commit.
For anything genuinely collaborative, the better answer is to move the stable code out of the notebook entirely.
When to move to a .py file
Notebooks are for exploration. Once code is settled, it should leave.
Move it when you find yourself copying the same function between notebooks, when the notebook exceeds roughly fifty cells, when something needs to run on a schedule, or when more than one person needs to change it.
The usual pattern in real projects is a hybrid: helper functions live in a .py module, and the notebook imports them and does the exploring. That gives you the interactive loop and code that can be tested and reviewed.
from src.cleaning import load_and_clean
df = load_and_clean("data.csv")
If a model or analysis is going into a project you will submit, put the real logic in modules — see the machine learning roadmap for how that fits into a workflow.
