csv.DictWriter

fieldnames fixes the columns and their order; each dict is looked up key by key. A key the dict lacks is filled with restval, a key fieldnames lacks is an error — and the header line is only written when you call writeheader().

csv classPython 2.3+Live demo
Common call
w = csv.DictWriter(f, fieldnames=["name", "age"]); w.writeheader(); w.writerows(rows)
Returns
writerow: what f.write returned; writerows: None
Replaces
writer.writerow([d[k] for k in keys]) by hand
Watch out
extra keys raise ValueError — extrasaction="ignore" drops them
csv.DictWriter(ff — A file opened with newline='' (or io.StringIO).type: object with write() · required, fieldnamesfieldnames — The columns, in output order.type: sequence of keys · required, restvalrestval — Written for a field name the dict has no key for.type: any · default: ''='', extrasactionextrasaction — What to do with keys that are not in fieldnames (case-insensitive).type: 'raise' | 'ignore' · default: 'raise'='raise', dialectdialect — Passed to csv.writer with any other keyword arguments (delimiter=…, quoting=…).type: str | Dialect · default: 'excel'='excel', *args, **kwds)
→ DictWriter

Demo

Live evaluation
Header + one dict built from your keys and values (comma-separated lists).
Try:
Inputs
fieldnameslist[str]columns
keyslist[str]dict keys
valueslist[str]dict values
Code
import csv, io
buf = io.StringIO(newline='')
w = csv.DictWriter(buf, fieldnames=['name', 'age'])
w.writeheader()
w.writerow(dict(zip(['name', 'age'], ['Ada', '36'])))
buf.getvalue()
Result
'name,age\r\nAda,36\r\n'

Columns always follow fieldnames, whatever order the dict has. A missing key is written as restval ('' by default), so "missing key" ends in two empty fields. An unknown key raises ValueError: dict contains fields not in fieldnames: 'age' — with several unknown keys they are listed in set order, which can change from run to run. In the second tab, the first dict is written before Bob's 'id' key stops writerows, so with 'raise' nothing at all comes out of the demo (the exception is what you see). extrasaction is lower-cased, so 'IGNORE' works; any other word is rejected by the constructor.

Parameters

NameTypeRequiredDescription
fobject with write()yesA file opened with newline='' (or io.StringIO).
fieldnamessequence of keysyesThe columns, in output order.
restvalanyno ('')Written for a field name the dict has no key for.
extrasaction'raise' | 'ignore'no ('raise')What to do with keys that are not in fieldnames (case-insensitive).
dialectstr | Dialectno ('excel')Passed to csv.writer with any other keyword arguments (delimiter=…, quoting=…).

Return value

DictWriter — An object with writeheader(), writerow(rowdict) and writerows(rowdicts); .writer is the underlying csv.writer.

Common patterns

Write a list of dicts to a CSV file
Take the column names from the first dict, or list them explicitly.
import csv
with open('people.csv', 'w', newline='', encoding='utf-8') as f:
    w = csv.DictWriter(f, fieldnames=['name', 'age'])
    w.writeheader()
    w.writerows(people)
Keep only some columns
extrasaction="ignore" drops the keys you do not list.
import csv
with open('export.csv', 'w', newline='', encoding='utf-8') as f:
    w = csv.DictWriter(f, fieldnames=['id', 'email'], extrasaction='ignore')
    w.writeheader()
    w.writerows(users)
Columns from all rows
When dicts have different keys, collect them first (dict.fromkeys keeps first-seen order).
import csv
fields = list(dict.fromkeys(k for row in rows for k in row))
with open('all.csv', 'w', newline='', encoding='utf-8') as f:
    w = csv.DictWriter(f, fieldnames=fields)
    w.writeheader()
    w.writerows(rows)

Examples

1. Header and rows
import csv, io buf = io.StringIO(newline='') w = csv.DictWriter(buf, fieldnames=['name', 'age']) w.writeheader() w.writerows([{'name': 'Ada', 'age': 36}, {'age': 41, 'name': 'Bob'}]) buf.getvalue()
Returns
'name,age\r\nAda,36\r\nBob,41\r\n'
2. Missing keys use restval
import csv, io buf = io.StringIO(newline='') csv.DictWriter(buf, ['a', 'b'], restval='NA').writerow({'a': 1}) buf.getvalue()
Returns
'1,NA\r\n'
3. Unknown keys raise
import csv, io csv.DictWriter(io.StringIO(), ['a']).writerow({'a': 1, 'b': 2})
Returns
ValueError: dict contains fields not in fieldnames: 'b'
4. extrasaction='ignore'
import csv, io buf = io.StringIO(newline='') csv.DictWriter(buf, ['a'], extrasaction='ignore').writerow({'a': 1, 'b': 2}) buf.getvalue()
Returns
'1\r\n'
5. Writer options pass through
import csv, io buf = io.StringIO(newline='') csv.DictWriter(buf, ['a', 'b'], delimiter=';', quoting=csv.QUOTE_ALL).writerow({'a': 1, 'b': 'x'}) buf.getvalue()
Returns
'"1";"x"\r\n'
6. writerow returns write()'s result
import csv, io csv.DictWriter(io.StringIO(), ['a', 'b']).writerow({'a': 'x', 'b': 'y'})
Returns
5
7. Bad extrasaction
import csv, io csv.DictWriter(io.StringIO(), ['a'], extrasaction='skip')
Returns
ValueError: extrasaction (skip) must be 'raise' or 'ignore'

Pitfalls

1. Forgetting writeheader()
Creating the DictWriter writes nothing. Without writeheader() the file has no column names.
no header
import csv, io
buf = io.StringIO(newline='')
w = csv.DictWriter(buf, ['name', 'age'])
w.writerow({'name': 'Ada', 'age': 36})
buf.getvalue()
'Ada,36\r\n'
writeheader() first
import csv, io
buf = io.StringIO(newline='')
w = csv.DictWriter(buf, ['name', 'age'])
w.writeheader()
w.writerow({'name': 'Ada', 'age': 36})
buf.getvalue()
'name,age\r\nAda,36\r\n'
2. Passing a list instead of a dict
DictWriter.writerow expects a mapping — a list has no .keys(), so the extrasaction check fails with AttributeError.
writerow(list)
import csv, io
csv.DictWriter(io.StringIO(), ['a', 'b']).writerow(['x', 'y'])
AttributeError: 'list' object has no attribute 'keys'
csv.writer for lists
import csv, io
buf = io.StringIO(newline='')
csv.writer(buf).writerow(['x', 'y'])
buf.getvalue()
'x,y\r\n'
3. Rows with more keys than the first one
Building fieldnames from rows[0] fails as soon as a later row has a new key.
rows[0].keys()
import csv, io
rows = [{'a': 1}, {'a': 2, 'b': 3}]
w = csv.DictWriter(io.StringIO(), fieldnames=rows[0].keys())
w.writerows(rows)
ValueError: dict contains fields not in fieldnames: 'b'
all keys
import csv, io
rows = [{'a': 1}, {'a': 2, 'b': 3}]
buf = io.StringIO(newline='')
w = csv.DictWriter(buf, fieldnames=list(dict.fromkeys(k for r in rows for k in r)))
w.writerows(rows)
buf.getvalue()
'1,\r\n2,3\r\n'

When to use

Use it
  • Your data is already a list of dicts (JSON records, database rows)
  • You want a fixed column order regardless of dict order
Reach for something else
  • Rows that are lists → csv.writer
  • Nested values (dicts inside dicts) → json, or flatten first

Notes

CPython impl
Lib/csv.py — class DictWriter: _dict_to_list checks rowdict.keys() - fieldnames, then yields rowdict.get(key, restval) for every field name; writerow/writerows delegate to csv.writer
Error order
The unknown-key message lists a set, so with several unknown keys their order varies between runs
Return value
writerow returns what the file's write() returned; writerows returns None

FAQ

Open the file with newline='', create csv.DictWriter(f, fieldnames=[...]), call writeheader(), then writerows(list_of_dicts).