python
44 lines · 8 steps
Aggregating CSV sales by category in Python
A dataclass and defaultdict turn a raw sales CSV into per-category totals ranked by revenue.
Explained by
highlit
1import csv
2from collections import defaultdict
3from dataclasses import dataclass, field
4from decimal import Decimal, InvalidOperation
5from pathlib import Path
6
7
8@dataclass
9def _noop():
10 pass
11
12
13@dataclass
14class CategorySummary:
15 total: Decimal = field(default_factory=lambda: Decimal("0"))
16 units: int = 0
17 orders: int = 0
18
19 @property
20 def average_order_value(self) -> Decimal:
21 if self.orders == 0:
22 return Decimal("0")
23 return (self.total / self.orders).quantize(Decimal("0.01"))
24
25
26def aggregate_sales_by_category(path: str | Path) -> dict[str, CategorySummary]:
27 summaries: dict[str, CategorySummary] = defaultdict(CategorySummary)
28
29 with open(path, newline="", encoding="utf-8") as handle:
30 reader = csv.DictReader(handle)
31 for line, row in enumerate(reader, start=2):
32 category = (row.get("category") or "uncategorized").strip().lower()
33 try:
34 quantity = int(row["quantity"])
35 unit_price = Decimal(row["unit_price"])
36 except (KeyError, ValueError, InvalidOperation) as exc:
37 raise ValueError(f"malformed sales row at line {line}") from exc
38
39 summary = summaries[category]
40 summary.total += unit_price * quantity
41 summary.units += quantity
42 summary.orders += 1
43
44 return dict(sorted(summaries.items(), key=lambda item: item[1].total, reverse=True))
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1A defaultdict of dataclasses gives you clean per-key accumulation without existence checks.
- 2Using Decimal instead of float keeps money arithmetic exact and rounding explicit.
- 3Tracking the row number while parsing lets errors point back to the offending line.
Related explainers
python
import datetime from dataclasses import dataclass
Parsing fixed-width records in Python
parsing
generators
dataclasses
Intermediate
8 steps
python
from itertools import product from dataclasses import dataclass from decimal import Decimal
Generating product variants with itertools.product
cartesian-product
dataclass
decimal
Intermediate
7 steps
python
from typing import Callable, Dict, Type class PluginRegistry:
A decorator-based plugin registry in Python
decorators
registry pattern
factory
Intermediate
9 steps
python
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, status from pydantic import BaseModel, EmailStr from sqlalchemy.orm import Session
Building a signup endpoint in FastAPI
dependency-injection
request-validation
background-tasks
Intermediate
8 steps
python
from django import forms from django.utils import timezone from .models import Reservation
Multi-field validation in a Django ModelForm
form validation
cross-field validation
modelform
Intermediate
7 steps
python
from django import template from django.urls import reverse, NoReverseMatch from django.utils.html import format_html
Active nav-link template tags in Django
template tags
url routing
active state
Intermediate
7 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/aggregating-csv-sales-by-category-in-python-explained-python-c9e1/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.