1.4.9 · D4Python & Scientific Computing

Exercises — Jupyter notebooks workflow

2,485 words11 min readBack to topic

Before we start, one picture ties the whole page together: what "the kernel remembers" actually means.

Figure — Jupyter notebooks workflow

Level 1 — Recognition

Goal: name the parts and read the signals Jupyter shows you.

Exercise 1.1

A cell shows In [ ] (empty brackets, no number). What does the empty bracket tell you, and what are the two distinct situations that both produce it?

Recall Solution

Empty brackets mean the cell has never been run in the current kernel session. The two situations:

  1. Fresh notebook / just-restarted kernel — no cell has run yet, so nothing has a number.
  2. A newly created cell you added but have not executed, even though other cells around it have numbers.

Contrast: In [*] (an asterisk) means the cell is currently running — the kernel is busy. In [7] means it finished as the 7th execution.

Exercise 1.2

You see this on screen, top to bottom: In [5]In [2]In [9]. Put these three cells in the order they were actually executed, and say what this pattern warns you about.

Recall Solution

The counter records execution order, so sort by the number: 2 → 5 → 9. On the page they sit in order 5, 2, 9 (top to bottom). Because the page order (5,2,9) is not the run order (2,5,9), the notebook was run out of order. Warning: a later cell may depend on a variable that only exists because you ran cells in this scrambled sequence. A fresh top-to-bottom run might fail.


Level 2 — Application

Goal: predict the exact printed output of a cell.

Exercise 2.1

A cell contains:

a = 3
b = 4
a + b
a * b

What renders below the cell, and why only that?

Recall Solution

Jupyter auto-displays only the value of the last expression in a cell. The last line is a * b, so it shows: The line a + b (value ) is computed and immediately thrown away — nothing else prints because there is no print(...) on it. If you wanted both, you would write print(a + b) then leave a * b as the final line.

Exercise 2.2

Two cells, run in this order:

Cell A

x = 5

Cell B

y = x * 2
y

What does Cell B display? Now the kernel is restarted and you run only Cell B. What happens?

Recall Solution

First run: after Cell A, the namespace is . Cell B computes so it displays .

After restart, the namespace is a fresh empty dictionary: . Running Cell B alone asks for x, which is not a key. Result: a NameError: name 'x' is not defined. The value lived only in memory, and restart wiped it.


Level 3 — Analysis

Goal: trace state through a messy execution order and find the bug.

Exercise 3.1

A student ran cells in this exact sequence (the number is the execution counter shown):

Ran Cell contents
In [1] data = load()
In [2] total = data.sum()
In [3] data = clean(data)
In [4] (re-runs Cell 2) total = data.sum()

Is the value of total after In [4] computed from the raw data or the cleaned data? Explain using the namespace.

Recall Solution

Track the key data in the namespace over time:

  • After In [1]: data → raw.
  • In [2]: total computed from raw.
  • In [3]: data is reassigned → cleaned. The raw version is gone; nothing still points to it.
  • In [4] re-runs the sum: it reads the current data, which is now the cleaned version.

So after In [4], total is from the cleaned data. Key idea: a cell always reads the latest value in the namespace, not the value that existed when you first wrote the cell.

Exercise 3.2

A notebook, read top to bottom on the page, looks like this:

# Cell 1
print(result)          # In [4]
# Cell 2
result = 42            # In [3]

It runs without error on the author's screen. A collaborator hits Restart & Run All and gets an error. Name the error and the exact fix, and explain why the author never saw it.

Recall Solution

The counters (In [4] above In [3]) reveal Cell 2 was run before Cell 1. So when Cell 1 printed result, the value already sat in the namespace — no error for the author.

"Restart & Run All" empties the namespace, then runs top to bottom: Cell 1 first. At that moment result does not exist yet → NameError: name 'result' is not defined.

Fix: reorder so the definition comes above the use (Cell 2's code before Cell 1's), then Restart & Run All to confirm a clean top-to-bottom pass.


Level 4 — Synthesis

Goal: design a clean, fast, reproducible notebook layout.

Exercise 4.1

You have one blob cell that takes 15 minutes total: load data (2 min), clean (3 min), train model (10 min). The model step keeps failing and you keep re-running the blob. Split it into cells and compute the time cost of one more debug cycle before and after the split.

Recall Solution

Before (one blob): every failed attempt re-runs everything.

After (three cells): load and clean already succeeded and their results (data, data_clean) sit in the namespace. To retry the model you re-run only the model cell:

Saving per cycle: Over, say, 6 debug attempts you save minutes. The dependencies live in memory, so you never pay for them twice.

Exercise 4.2

Using the EDA flow from the parent, arrange these five actions into five separate cells in the correct order, and for each cell state the one conceptual job it does: imports · fit a LinearRegression on ['ad_spend', 'season'] · read_csv · data.describe() · histogram of revenue.

Recall Solution

Order follows the data's life cycle — you cannot explore data you haven't loaded, nor model features you haven't seen.

Cell Code job One conceptual thing
1 import pandas as pd, import numpy as np, matplotlib bring in tools
2 data = pd.read_csv('sales.csv') load data
3 data.describe() numeric summary (last expr auto-shows)
4 data['revenue'].plot(kind='hist') visual summary
5 LinearRegression().fit(data[['ad_spend','season']], y) model

Each cell does exactly one thing, so if cell 5 fails you re-run only cell 5 — cells 1–4 are still cached in the namespace. See 1.5.01-Pandas-DataFrames and 1.6.01-Matplotlib-basics for the tools in cells 2–4.


Level 5 — Mastery

Goal: reason about the whole system — memory, reproducibility, and edge cases.

Exercise 5.1

The execution counter is defined as Start from a fresh kernel. You run: Cell A, Cell B, Cell A again, Cell C. Write the In [n] shown on each cell at the end.

Recall Solution

Apply the rule step by step (fresh kernel → max starts effectively at ):

Action new A B C
run A 1 1
run B 2 1 2
run A 3 3 2
run C 4 3 2 4

Final labels displayed: A shows In [3], B shows In [2], C shows In [4]. Notice A's first number () was overwritten when it re-ran; a cell only ever shows its most recent execution number.

Exercise 5.2

A cell mutates a list in place and is run twice:

nums = [1, 2, 3]
nums.append(nums[-1] + 1)
nums

Cell 1 defines nums; Cell 2 is the append line above. You run Cell 1 once, then run Cell 2 three times. What is the final value of nums? Then predict the value if you had instead run "Restart & Run All" (each cell once).

Recall Solution

Repeated Cell 2 (no restart): nums persists in the namespace and each run appends one element built from the current last element.

  • start:
  • run 1: last append
  • run 2: last append
  • run 3: last append

Final: — length . Re-running a mutating cell accumulates side effects because the object survives between runs.

Restart & Run All (each once): namespace reset; Cell 1 rebuilds nums = [1,2,3], Cell 2 appends once: The gap between and is exactly why "works for me" fails for others — hidden repeated mutations. This is a core lesson for debugging notebooks.

Exercise 5.3 (edge case)

An empty kernel: you run a cell that contains only a comment # TODO. What is displayed below it, and what In [n] does it get?

Recall Solution

A comment-only cell has no expression to evaluate, so nothing renders below it — the output area stays blank (not None, not an error). It still counts as an execution: from an empty kernel it gets In [1]. The counter tracks runs, and running an empty cell is still a run. Edge takeaway: "no output" and "did not run" look different — check the bracket (In [1] vs In [ ]) to tell them apart.


Recall

Quick self-check reveals: In [*] means ::: the cell is currently running (kernel busy). A restarted kernel's namespace is ::: a fresh empty dictionary — all variables gone. Auto-display shows ::: only the value of the last expression in the cell. "Done" for sharing means ::: passes Restart & Run All top-to-bottom with no error. Re-running a mutating cell ::: accumulates side effects because the object survives between runs.