Warming up the neural circuits...
By the end of this chapter you will:
Data and AI work is rarely linear. You test one assumption, inspect output, then pivot.
That workflow is painful in plain scripts because every tiny change needs a rerun of setup code. Notebooks give you a stateful REPL with rich output so exploration becomes fast.
Mental model: a notebook is a whiteboard with memory. Great whiteboards need discipline, or yesterday's marker lines become today's bug.
import platform
import sys
print(sys.executable)
print(platform.python_version())
# C:\om workspace\LEARNING-HUB\.venv\Scripts\python.exe
# 3.12.4If these values do not match teammate expectations, your notebook may run "fine" while producing non-reproducible results.
counter = 0
counter += 1
print(counter)
# 1 (first run)
# 2 (if you run this same cell again)Notebook cells are mutable steps in one process. "Run all top-to-bottom" is the only reliable truth test.
%timeit sum(range(10_000))
# 130 us +- 6 us per loop (mean +- std. dev. of 7 runs)%pip install pandas==2.2.2
# Successfully installed pandas-2.2.2Prefer %pip inside notebooks so the active kernel receives the package, not some other global Python.
import pandas as pd
from IPython.display import Markdown, display
df = pd.DataFrame({"city": ["Pune", "Delhi"], "orders": [120, 98]})
display(Markdown("
Rich outputs reduce context-switching and speed up debugging of assumptions.
# analytics/transforms.py
from collections.abc import Sequence
def zscore(values: Sequence[float]) -> list[float]:
mean = sum(values) / len(values)
variance = sum
# notebook cell
from analytics.transforms import zscore
print([round(x, 2) for x in zscore([10.0, 12.0, 14.0])])
# [-1.22, 0.0, 1.22]Keep exploration in notebooks, move reusable logic into modules, then call modules from notebooks.
Notebook JSON diffs are noisy, merge conflicts are common, and test coverage is often ignored.
Recommended boundary:
Notebook code is trusted only after a fresh kernel restart and a full Run All succeeds without manual edits.
| Step | Tooling choice | Why it matters |
|---|---|---|
| Create env | python -m venv .venv | Prevent global package drift |
| Select kernel | VS Code kernel picker / JupyterLab | Binds notebook to the right interpreter |
| Explore | Notebook cells + rich output | Fast hypothesis loop |
| Stabilize | Move functions into .py modules | Enables tests and reuse |
| Validate | Restart kernel + Run All | Detects hidden state bugs |
| Share | Export summary, commit module code | Cleaner collaboration and review |
| Mistake | Why it hurts | Better move |
|---|---|---|
NameError: name 'df' is not defined after rerun | Cell order dependency and hidden state | Run notebook from top after kernel restart |
ModuleNotFoundError: No module named 'pandas' | Package installed outside active kernel | Use %pip install ... in notebook kernel |
SyntaxError: invalid syntax from pip install numpy in a cell | Shell command run as Python code | Use %pip ... or !pip ... |
FileNotFoundError: [Errno 2] No such file or directory: 'data/orders.csv' | Relative path assumes wrong working directory | Use Path.cwd() checks and explicit paths |
Large .ipynb merge conflicts | Notebook JSON is hard to diff and resolve | Keep logic in modules and notebooks focused on analysis |
Fresh notebookInterpreter path + Python version linesNotebook with 3 cellsSame outputs after full restart-run%timeit to compare a Python loop vs built-in/vectorized style operation.Two implementations of the same taskClear timing difference captured in output.py module and import it back.Notebook helper functionImport works and function output matchesCurrent project notebook5-step runbook (env, kernel, data path, run-all, expected outputs)Beginner:
"Why are notebooks popular for data work?"
They combine code, output, and narrative in one place, which accelerates exploratory analysis and communication.
"What does kernel selection control?"
It controls interpreter version and package environment for that notebook session.
Senior:
"How do you prevent notebook experiments from becoming unmaintainable production code?"
Keep exploration in notebooks, move stable logic to tested modules, and enforce restart-run-all reproducibility before sharing.
"What governance checks would you add for a team that ships notebook-driven analyses?"
Environment pinning, data/version metadata, deterministic execution checks, and CI for module logic extracted from notebooks.
%timeit, %pip, and rich display speed up feedback loops when used intentionally.Need fast exploration -> Notebook cells + rich display
Need reproducibility -> Restart kernel + Run All
Need package alignment -> Use active kernel + %pip
Need maintainability -> Move reusable logic into .py modules
Need team collaboration -> Keep notebooks thin, modules testedWhat is the most reliable notebook correctness check before sharing results?