csv.writer

writer(f).writerow(row) formats one row and calls f.write() with it. Every value goes through str(), None becomes an empty field — and the row ends in \r\n, which is why the file needs newline=''.

csv functionPython 2.3+Live demo
Common call
csv.writer(f).writerows(rows)
Returns
writerow: what f.write returned (the number of characters for text files)
Replaces
f.write(','.join(row) + '\n'), which breaks on commas and quotes
Watch out
open(path, 'w', newline='') — or Windows adds blank rows
csv.writer(csvfilecsvfile — A file opened with newline='', io.StringIO, or anything with a write(str) method.type: object with write() · required, dialectdialect — A registered name ('excel', 'excel-tab', 'unix') or a Dialect class/instance.type: str | Dialect · default: 'excel'='excel', **fmtparams**fmtparams — Override single settings: delimiter, quotechar, escapechar, doublequote, quoting, lineterminator, skipinitialspace.type: keyword arguments · default: null)
→ _csv.writer

Demo

Live evaluation
One row of three values. Numbers are typed as numbers (7, 2.5). The result shows what writerow returned and what was written.
Try:
Inputs
astr | int | floatfield 1
bstr | int | floatfield 2
cstr | int | floatfield 3
Code
import csv, io
buf = io.StringIO(newline='')
w = csv.writer(buf)
n = w.writerow(['Ada', 36, 1.5])
(n, buf.getvalue())
Result
(12, 'Ada,36,1.5\r\n')

writerow returns whatever the file's write() returned — for io.StringIO and text files that is the number of characters written, including the two of "\r\n". In the quoting tab, None is written as an empty field: QUOTE_ALL and QUOTE_NONNUMERIC quote it (""), QUOTE_STRINGS and QUOTE_NOTNULL leave it bare so it can be told apart from the quoted empty string; QUOTE_NONNUMERIC leaves the int 36 bare. A quoting value outside 0–5 is TypeError: bad "quoting" value. Under QUOTE_NONE the escapechar is put before every delimiter and quote character; without one the writer raises csv.Error.

Parameters

NameTypeRequiredDescription
csvfileobject with write()yesA file opened with newline='', io.StringIO, or anything with a write(str) method.
dialectstr | Dialectno ('excel')A registered name ('excel', 'excel-tab', 'unix') or a Dialect class/instance.
fmtparamskeyword argumentsnoOverride single settings: delimiter, quotechar, escapechar, doublequote, quoting, lineterminator, skipinitialspace.

Return value

_csv.writer — An object with writerow(row), writerows(rows) and a read-only dialect attribute.

Common patterns

Write a header and rows
newline='' on the open() is the one thing not to forget.
import csv
with open('out.csv', 'w', newline='', encoding='utf-8') as f:
    w = csv.writer(f)
    w.writerow(['name', 'age'])
    w.writerows([['Ada', 36], ['Bob', 41]])
CSV text in memory
io.StringIO collects the output, e.g. for an HTTP response.
import csv, io
buf = io.StringIO(newline='')
csv.writer(buf).writerows(rows)
text = buf.getvalue()
Unix line endings
lineterminator='\n' (or dialect='unix', which also quotes everything).
import csv
with open('out.csv', 'w', newline='', encoding='utf-8') as f:
    csv.writer(f, lineterminator='\n').writerows(rows)

Examples

1. writerows writes many rows
import csv, io buf = io.StringIO(newline='') csv.writer(buf).writerows([['a', 1], ['b', 2]]) buf.getvalue()
Returns
'a,1\r\nb,2\r\n'
2. Values go through str()
import csv, io buf = io.StringIO(newline='') csv.writer(buf).writerow([1.5, True, None, [1, 2]]) buf.getvalue()
Returns
'1.5,True,,"[1, 2]"\r\n'
3. A lone empty field is quoted
import csv, io buf = io.StringIO(newline='') csv.writer(buf).writerows([[''], ['', '']]) buf.getvalue()
Returns
'""\r\n,\r\n'
4. Semicolons for European Excel
import csv, io buf = io.StringIO(newline='') csv.writer(buf, delimiter=';').writerow(['Tea', '2,50']) buf.getvalue()
Returns
'Tea;2,50\r\n'
5. Custom line terminator
import csv, io buf = io.StringIO(newline='') csv.writer(buf, lineterminator='\n').writerows([['a'], ['b']]) buf.getvalue()
Returns
'a\nb\n'
6. writerows returns None
import csv, io csv.writer(io.StringIO()).writerows([['a']]) is None
Returns
True
7. A row must be iterable
import csv, io csv.writer(io.StringIO()).writerow(42)
Returns
_csv.Error: iterable expected, not int

Pitfalls

1. Passing a string as the row
writerow iterates its argument. A str is an iterable of characters, so every letter becomes its own field.
writerow('abc')
import csv, io
buf = io.StringIO(newline='')
csv.writer(buf).writerow('abc')
buf.getvalue()
'a,b,c\r\n'
writerow(['abc'])
import csv, io
buf = io.StringIO(newline='')
csv.writer(buf).writerow(['abc'])
buf.getvalue()
'abc\r\n'
2. Blank rows: no newline='' when the OS translates \n
On Windows a text file opened without newline='' writes every \n as \r\n, so the writer's \r\n ends up as \r\r\n. newline='\r\n' below reproduces that on any OS.
translated
import csv
with open('t.csv', 'w', newline='\r\n') as f:
    csv.writer(f).writerow(['a', 'b'])
with open('t.csv', 'rb') as f:
    raw = f.read()
raw
b'a,b\r\r\n'
newline=''
import csv
with open('t.csv', 'w', newline='') as f:
    csv.writer(f).writerow(['a', 'b'])
with open('t.csv', 'rb') as f:
    raw = f.read()
raw
b'a,b\r\n'
3. Joining with commas by hand
','.join does not quote anything, so a value with a comma silently becomes two columns.
','.join
import csv
line = ','.join(['Paris, TX', '2'])
next(csv.reader([line]))
['Paris', ' TX', '2']
csv.writer
import csv, io
buf = io.StringIO(newline='')
csv.writer(buf).writerow(['Paris, TX', '2'])
next(csv.reader([buf.getvalue()]))
['Paris, TX', '2']

When to use

Use it
  • Exporting lists/tuples of values to a spreadsheet-readable file
  • Generating CSV text for downloads or APIs (with io.StringIO)
Reach for something else
  • Rows that are dicts → csv.DictWriter
  • Data with nesting → json

Notes

CPython impl
Modules/_csv.c — csv_writerow joins the fields in a buffer (join_append_data decides quoting and escaping per character), adds lineterminator and makes ONE write() call per row
Quoting rule
QUOTE_MINIMAL quotes a field containing the delimiter, quotechar, \r, \n or any character of lineterminator; a quotechar inside is doubled (doublequote=True)
None
Written as an empty field; QUOTE_STRINGS / QUOTE_NOTNULL (3.12+) leave it unquoted so readers can map it back to None

FAQ

You opened the file without newline='' on Windows. The writer ends rows with \r\n; text mode turns the \n into \r\n again. Use open(path, 'w', newline='', encoding='utf-8').