Time to use what you have learned. This project is typical of real office, finance and analyst work: take a CSV export, find out where the money goes and print a short report. It combines files, dictionaries, loops, sorting and formatted output. You do not need any extra packages. Later, if you move on to data work, tools such as pandas do the same job with less code, but doing it by hand first helps you understand what they do.
The data
Save this as expenses.csv in your project folder. It is a made-up set of expenses for one month. Each row has a date, a category, a description and an amount.
date,category,description,amount
2026-01-03,Food,Groceries,1250.50
2026-01-04,Travel,Metro card,500
2026-01-09,Food,Lunch with team,320
2026-01-12,Bills,Electricity,1800
2026-01-15,Food,Dinner out,780
2026-01-20,Travel,Taxi,260.75
2026-01-25,Bills,Internet,999
2026-01-28,Fun,Movie,450
The goal
We want a table that shows, for each category, the total amount and its share of all spending, the biggest categories first. We also want the biggest single expense. Plan the steps before you write code.
- Open the CSV and read each row as a dictionary.
- Convert the amount from text to a number.
- Add the amount to the total of its category, and remember the biggest expense so far.
- Work out the grand total.
- Sort the categories by total, from the biggest.
- Print a neat table.
The program
import csv
from collections import defaultdict
from pathlib import Path
here = Path(__file__).parent
totals = defaultdict(float)
biggest = None
with open(here / "expenses.csv", newline="", encoding="utf-8") as f:
for row in csv.DictReader(f):
amount = float(row["amount"])
totals[row["category"]] += amount
if biggest is None or amount > biggest["amount"]:
biggest = {"description": row["description"], "amount": amount}
grand_total = sum(totals.values())
print(f"{'Category':<10}{'Total':>10}{'Share':>8}")
for category, total in sorted(totals.items(), key=lambda item: item[1], reverse=True):
print(f"{category:<10}{total:>10.2f}{total / grand_total:>8.0%}")
print(f"{'All':<10}{grand_total:>10.2f}")
print("Biggest:", biggest["description"], biggest["amount"])
Category Total Share
Bills 2799.00 44%
Food 2350.50 37%
Travel 760.75 12%
Fun 450.00 7%
All 6360.25
Biggest: Electricity 1800.0
How it works
Path(__file__).parentis the folder where this script lives. Building the path from it means that the program findsexpenses.csvwherever you start it from.defaultdict(float)starts every new category at0.0, sototals[row["category"]] += amountworks even the first time a category appears.- The
biggestvariable starts asNone. The first row replaces it, and later rows replace it only if their amount is larger. sorted(totals.items(), key=lambda item: item[1], reverse=True)sorts the pairs by total, with the largest first.- In the f-string,
{total / grand_total:>8.0%}formats a fraction as a percentage with no decimals. 2799 divided by 6360.25 is 44 percent. - The
Allrow repeats the total, and you can check it by adding the categories by hand: 2799 plus 2350.50 plus 760.75 plus 450 is 6360.25.
Checking your work
A report that looks neat can still be wrong. Check it in a second way. Add up the amounts in the file by hand, or with a calculator, or in a spreadsheet, and compare it with the program total. Check one category by hand too. For Food, the rows are 1250.50, 320 and 780, and their sum is 2350.50, exactly as printed. When your program and a hand check agree, you can trust it.
Make it your own
- Add a command-line option for the month or the file name (lesson 15 shows
argparse). - Write the report into a file, with
Path.write_text, so you can send it to someone. - Find expenses above a limit, such as 1000, and list them.
- Group by month. Use the date column:
row["date"][:7]gives2026-01. - Handle bad rows. If an amount is not a number,
float()raises aValueError. Decide whether to skip the row and print a warning, or stop. Lesson 9 shows how.
From here to data jobs
Reading a file, cleaning it, grouping, summing and reporting is the heart of many data and office automation tasks. If you want to go further, look at pandas for tables and matplotlib for charts. Those are separate packages that you install with pip in a virtual environment (lesson 10). Learn the basics in this course first. They make every later tool easier to understand.
Your task
- Save
expenses.csvand the program. Run it and compare each total with a hand calculation. - Add a line that prints the average expense and the number of expenses.
- Add a second report that lists every expense over 700, one per line.
- Add three more rows to the CSV, including a new category, and check that the report updates.
How to check it worked
- The report shows Bills 2799.00, Food 2350.50, Travel 760.75, Fun 450.00 and All 6360.25.
- The biggest expense is
Electricity 1800.0. - The program still works after you add rows with a new category.