The accountant wants a CSV, and the drink 'Latte, oat' breaks every naive split. The csv module knows about quotes. What does DictReader assume about the first row?
CSV looks simple until a value contains a comma, a quote, or a newline. The csv module handles those details and can expose each row as a dictionary keyed by the header. Use StringIO for small examples so the exercise does not leave files behind. You will also handle uneven columns, strict writers, and byte-order marks.
Read rows as dictionaries
DictReader treats the first row as field names by default. Each subsequent row becomes a dictionary. This is easier to read than remembering column positions, especially when the source has many columns.
import csv
from io import StringIO
raw = "name,score\nAda,92\nGrace,88\n"
rows = list(csv.DictReader(StringIO(raw)))
print(rows[0]["name"])Header names become keys
Write rows with a writer
csv.writer writes one row at a time and adds the line terminator. Pass a list or tuple of fields. For a small in-memory example, write into StringIO and inspect getvalue().
import csv
from io import StringIO
buffer = StringIO()
writer = csv.writer(buffer)
writer.writerow(["name", "score"])
writer.writerow(["Ada", 92])
print(buffer.getvalue().strip())Build CSV text in memory
Quote fields that need it
A comma inside a field must be protected by quotes. QUOTE_ALL quotes every field, which is useful when another tool expects it. The reader will remove the quotes and return the original value.
import csv
from io import StringIO
buffer = StringIO()
writer = csv.writer(buffer, quoting=csv.QUOTE_ALL)
writer.writerow(["a,b", "c"])
print(buffer.getvalue().strip())Commas inside a field
DictReader: missing and extra columns
DictReader uses the header row as keys. A short row fills missing fields with None; extra fields go into the key named by restkey. Check both cases at the boundary instead of assuming every row has exactly the expected shape.
import csv
import io
text = "name,price\nlatte,4.5\ntea\nmocha,5.0,note\n"
reader = csv.DictReader(io.StringIO(text), restkey="extra")
for row in reader:
print(row["name"], row.get("price"), row.get("extra"))A header does not guarantee a full row
DictWriter: field order and strict extras
fieldnames fixes the column order. extrasaction='raise' turns an unexpected key into an error instead of silently dropping it. A fixed lineterminator makes output reproducible across platforms and avoids double newlines on Windows.
import csv
import io
out = io.StringIO(newline="")
fields = ["name", "price"]
writer = csv.DictWriter(
out, fieldnames=fields, extrasaction="raise", lineterminator="\n"
)
writer.writeheader()
writer.writerow({"name": "latte", "price": 4.5})
try:
writer.writerow({"name": "tea", "price": 3.0, "note": "hot"})
except ValueError as error:
print(type(error).__name__, error)
print(repr(out.getvalue()))Fail loudly on an unexpected column
Handle a BOM and line endings at the boundary
Spreadsheet exports often start with a UTF-8 byte-order mark. Decode with utf-8-sig so the first header does not become \ufeffname. Open text streams with newline='' so the csv module, not the platform, controls row endings.
import csv
import io
raw = b"\xef\xbb\xbfname,price\r\nlatte,4.5\r\n"
text = raw.decode("utf-8-sig")
reader = csv.DictReader(io.StringIO(text, newline=""))
row = next(reader)
print(row["name"], row["price"])
out = io.StringIO(newline="")
writer = csv.writer(out, lineterminator="\n")
writer.writerow(["tea", 3.0])
print(repr(out.getvalue()))Decode the BOM once, then parse
Key points
- Use csv.reader or csv.DictReader instead of splitting on commas.
- DictReader uses the first row as headers by default.
- writerow writes one row and adds a line terminator.
- Quoting protects commas, quotes, and newlines inside fields.
- Use StringIO for small in-memory examples.
- Check row shape; make writer extras strict; decode utf-8-sig and control newlines.
Common mistakes
- Using line.split(",") when a field contains a comma.
- Forgetting that DictReader values are strings unless you convert them.
- Opening a file for csv writing without newline="" on platforms that translate line endings.
- Opening CSV text without newline='' and then blaming csv for blank lines.
Parse 'name,score\nAda,92\n' with DictReader and print Ada's score.
Try it yourself
Change the values, predict the output, then run the code. The Python runtime is downloaded the first time you press Run, so the first run can take a few seconds.
Practice this lesson
12 questions with immediate explanations.