Write CSV files with a header
`csv.DictWriter` writes a header and one line per dictionary, quoting values that contain commas or quotes, so any spreadsheet or CSV reader can read the file back.
- Create a
csv.DictWriterwith the column order, write the header once and then the rows - Explain what
newline=""prevents and how values with commas and quotes are written - Choose columns from wider rows with
extrasaction="ignore", and read one CSV while writing another
Writing CSV by gluing strings breaks the moment a value contains a comma. csv.DictWriter(file, fieldnames=[...]) takes the column order once, writeheader() writes the header line, and writerow(row) (or writerows(rows)) writes each dictionary's values in that order, quoting any value that contains a comma, a quote or a line break.
Open the file with newline="". The csv module ends each line with \r\n itself, as the CSV standard asks; without newline="", Windows would turn that \n into another \r\n and the file would show a blank line between rows.
Run each example to see what it prints. Running examples doesn't count toward progress.
import csv rows = [ {"sku": "HOM-52782", "name": "Deluxe Pillow", "price": 47.99}, {"sku": "BOO-58412", "name": "Handbook, Nordic edition", "price": 15.99}, ] with open("products.csv", "w", encoding="utf-8", newline="") as out: writer = csv.DictWriter(out, fieldnames=["sku", "name", "price"]) writer.writeheader() writer.writerows(rows) with open("products.csv", encoding="utf-8", newline="") as source: print(repr(source.read()))
DictWriter is strict about extra keys. Rows from another source often carry more fields than the export should have, and writing one raises an error rather than silently dropping data.
import csv with open("export.csv", "w", encoding="utf-8", newline="") as out: writer = csv.DictWriter(out, fieldnames=["order_id", "total"]) writer.writeheader() writer.writerow({"order_id": "O100043", "total": 12.93, "status": "delivered"})
import csv def export_columns(src, dest, columns): count = 0 with open(src, encoding="utf-8", newline="") as source, open(dest, "w", encoding="utf-8", newline="") as out: writer = csv.DictWriter(out, fieldnames=columns, extrasaction="ignore") writer.writeheader() for row in csv.DictReader(source): writer.writerow(row) count += 1 return count with open("customers.csv", "w", encoding="utf-8", newline="") as out: out.write("customer_id,first_name,last_name,email,city,state\n") out.write("C00164,Isaac,Sato,isaac.sato62@gmail.com,New York,NY\n") out.write("C00800,Samuel,Mensah,samuel_mensah@yahoo.com,Miami,FL\n") print(export_columns("customers.csv", "mailing.csv", ["email", "first_name"])) with open("mailing.csv", encoding="utf-8", newline="") as source: for row in csv.reader(source): print(row)
When to use it: any time you hand data to a spreadsheet, another team or another program. Mistakes to avoid: writing the header inside the loop (once per row), opening without newline="", and building lines with ",".join(...), which breaks on the first value that contains a comma.
csv.DictWriter(out, fieldnames=[...]), thenwriteheader()once, thenwriterow/writerows.- Open with
newline=""; the module writes\r\nand quotes values that need it. - Extra keys raise ValueError unless
extrasaction="ignore"; missing keys become empty values. - Next: JSON, for data with nesting, lists and real types.