Python for Actuarial Students · Course 0W
Module 8 · Part A

Your First Python Project

Project structure, your first script, and notebooks in a managed environment — every tool from this course, working together.

Module 8 · OverviewTwo parts

Part A — this deck

  • A standard project layout: src, data, notebooks, output, tests
  • Writing and running hello.py with uv run
  • Notebooks inside the managed environment
  • How notebooks display output — with and without print()

≈ 40 min, including a checkpoint exercise

Part B — next deck

  • A taste of Python: print(), arithmetic, NumPy, pandas
  • Charts with matplotlib and seaborn
  • Exporting notebooks to HTML and PDF
  • The final hands-on lab

≈ 90 min, including the lab

Companion notebook: module-08a-first-project.ipynb — worked examples and self-checking exercises.

The big pictureEverything you’ve built, working together

WorkspaceC:\actuarial_work
Module 1
→
TerminalPowerShell, PATH
Modules 2–3
→
uvPython + packages
Module 4
→
Githistory + backup
Module 5
→
DocsMarkdown + notebooks
Module 6
→
VS Codeone window
Module 7

Today the tools fade into the background, and Python takes center stage.

Part 1

Project Structure

A place for everything, and everything in its place.

StructureA standard layout

actuarial_intro\
├── .venv\            managed by uv — never touch
├── .vscode\          editor config (Module 7)
├── data\
│   └── raw\           inputs, read-only, not in Git
├── notebooks\        exploration & reports
├── output\           charts, exports — regenerable
├── src\              reusable Python code
├── tests\            checks that code is right
├── .gitignore
├── .python-version
├── pyproject.toml
├── README.md
└── uv.lock
FolderRule of thumb
data\rawNever edited by hand or by code. The source of truth.
srcScripts and functions you trust and reuse
notebooksNumbered: 01_load.ipynb, 02_explore.ipynb…
outputAnything code produces. Safe to delete and rebuild.
testsAutomated checks (future courses)

StructureWhy bother?

Raw data stays raw

You can always rerun from the original extract. No “which version of the CSV did I clean?”.

Code is separate from results

Delete output\, rerun, and get the same numbers. That’s reproducibility.

Others can find things

A colleague — or a reviewer — opens any project and knows where to look.

This is the same discipline as a well-built Excel model: separate input, calculation, and output tabs — enforced by folders instead of goodwill.

StructureCreating it

cd C:\actuarial_work
uv init actuarial_intro --python 3.12
cd actuarial_intro
mkproj .                       # your Module 3 script!
mkdir data\raw

No mkproj? Plain PowerShell does it too:

mkdir src, data\raw, notebooks, output, tests

Git doesn’t track empty folders. Drop an empty placeholder file in any folder you want to keep:

ni tests\.gitkeep, output\.gitkeep

uv init made a main.py at the top level. We’ll keep code in src\, so delete it: rm main.py

Part 2

Your First Script

hello.py, run the uv way.

hello.pyWrite it, run it

In VS Code: right-click src → New File… → hello.py

"""hello.py — my first Python script."""

name = "Actuarial Student"
years_to_exam = 0.5

print(f"Hello, {name}!")
print("Weeks until exam:", years_to_exam * 52)

In the terminal (Ctrl+`), from the project root:

PS C:\actuarial_work\actuarial_intro> uv run python src/hello.py
Hello, Actuarial Student!
Weeks until exam: 26.0

Forward slash in src/hello.py — works on every OS (Module 1). The ▷ button in VS Code does the same, using the .venv interpreter.

hello.pyWhat just happened?

uv runchecks .venv matches uv.lock
→
python.exefrom .venv starts
→
Reads the filetop to bottom, one line at a time
→
Exitsall variables forgotten
  • """…""" on line 1 is a docstring — a description of the file
  • name = … creates a variable: a label attached to a value
  • f"…{name}…" is an f-string: values dropped into text
  • print() writes to the terminal

A script runs fresh, top to bottom, every time. That makes it predictable — the opposite of a notebook’s hidden state.

Part 3

Notebooks in the Managed Environment

Two front-ends, one environment.

NotebooksScripts or notebooks?

Script (.py)Notebook (.ipynb)
RunsTop to bottom, every timeCell by cell, in any order
Best forRepeatable jobs, reusable functionsExploring data, explaining results
OutputTerminal text, filesRich tables and charts, saved inline
In GitClean, readable diffsJSON — noisier diffs
Lives insrc\notebooks\

Explore in a notebook; once something works, move it into a script.

NotebooksTwo ways to open one — same environment

Jupyter Lab in the browser

uv add --dev jupyterlab
uv run jupyter lab

Navigate to notebooks\ → New → Notebook.

VS Code

  1. Ctrl+Shift+P → Create: New Jupyter Notebook
  2. Select Kernel → Python Environments → .venv
  3. Save as notebooks\01_hello.ipynb

Needs ipykernel in the environment — jupyterlab brings it along.

Either way, the kernel is the project’s .venv Python, so the notebook sees exactly the packages in uv.lock.

NotebooksGotcha: where is “here”?

Relative paths start from the current working directory (Module 1) — and it differs:

Running…CWD is…Data path
a script via uv run from the rootproject rootdata/raw/x.csv
a notebook in notebooks\notebooks\../data/raw/x.csv

Check any time:

from pathlib import Path
Path.cwd()
# WindowsPath('C:/actuarial_work/actuarial_intro/notebooks')

A robust habit in notebooks:

DATA = Path("..") / "data" / "raw"
df = pd.read_csv(DATA / "policies.csv")

DisplayOutput with and without print()

[1]:
rate = 0.05 rate
[1]:
0.05
[2]:
print(rate)
0.05
[3]:
rate * 2 rate * 3
[3]:
0.15000000000000002
[4]:
x = rate * 100
  • The last expression in a cell is displayed automatically, with an Out[n] label
  • print() output appears with no Out label — and works anywhere in the cell
  • Only the last bare expression shows — cell 3 hides rate * 2
  • An assignment (cell 4) displays nothing

And yes, 0.15000000000000002 — computers store decimals in binary. Round for display: round(rate * 3, 4).

DisplayRich display for tables and charts

[5]:
df = pd.DataFrame({"age": [30, 40], "qx": [0.0008, 0.0016]}) df
[5]:
ageqx
0300.0008
1400.0016
[6]:
print(df)
age qx 0 30 0.0008 1 40 0.0016
Want…Use
A formatted tableEnd the cell with df
Several tables from one celldisplay(df.head())
display(df.describe())
Plain text (as a script would print)print(df)
To hide an unwanted OutEnd the line with ;

display() is built into Jupyter — no import needed. In a .py script, only print() shows anything.

Checkpoint · 15 minScaffold, script, notebook

  1. Create actuarial_intro with uv init and the standard folders
  2. Write src\hello.py; run it with uv run python src/hello.py
  3. uv add --dev jupyterlab; create notebooks\01_hello.ipynb using the .venv kernel
  4. Reproduce the display examples: bare expression, print(), two expressions in one cell, a semicolon
  5. Print Path.cwd() from both the notebook and the script. Explain the difference.

Keep this project — Part B builds on it, and the final lab commits it to Git.

Stretch: git init (if uv didn’t), extend .gitignore from Module 5, and make a first commit now.

Up next
Module 8 · Part B

A Taste of Python

Arithmetic, NumPy, pandas, and charts — then publish your notebook and commit the finished project.