csv.reader

Give it anything that yields lines of text — an open file, a list of strings, io.StringIO — and iterate. Every field comes back as a str, and the file must be opened with newline=''.

csv functionPython 2.3+Live demo
Common call
for row in csv.reader(f): ...
Returns
['Ada', '36'] per row — always strings
Replaces
line.strip().split(',') loops that break on quoted commas
Watch out
open the file with newline='' — and in text mode, not 'rb'
csv.reader(csvfilecsvfile — Anything that yields lines: a file opened with newline='', a list of strings, io.StringIO.type: iterable of str · 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, skipinitialspace, quoting, strict, lineterminator.type: keyword arguments · default: null)
→ _csv.reader

Demo

Live evaluation
Type CSV text (\n = line break) and choose the delimiter and quote character.
Try:
Inputs
textstrCSV text, \n = line break
delimiterstrone character
quotecharstrone character
Code
import csv, io
text = 'id,name\\n1,"Smith, John"'.replace('\\n', '\n')
list(csv.reader(io.StringIO(text, newline=''), delimiter=',', quotechar='"'))
Result
[['id', 'name'], ['1', 'Smith, John']]

line_num is read after each row is produced, so a row whose quoted field spans two lines advances it by 2, and a blank line produces an empty list []. In strict: a quote that opens a field must be followed by the delimiter or the end of the line once it closes — "b"c is accepted as bc normally and is "',' expected after '"'" with strict=True. A quote in the middle of an unquoted field is just a character either way.

Parameters

NameTypeRequiredDescription
csvfileiterable of stryesAnything that yields lines: a file opened with newline='', a list of strings, io.StringIO.
dialectstr | Dialectno ('excel')A registered name ('excel', 'excel-tab', 'unix') or a Dialect class/instance.
fmtparamskeyword argumentsnoOverride single settings: delimiter, quotechar, escapechar, doublequote, skipinitialspace, quoting, strict, lineterminator.

Return value

_csv.reader — An iterator: each next() returns one row as a list of str (one row may span several input lines).

Common patterns

Loop over a file
newline='' lets the reader see line breaks inside quoted fields exactly as written.
import csv
with open('data.csv', newline='', encoding='utf-8') as f:
    for row in csv.reader(f):
        print(row)
Skip the header row
next() on the reader consumes one row.
import csv
with open('data.csv', newline='', encoding='utf-8') as f:
    rows = csv.reader(f)
    header = next(rows)
    data = [row for row in rows]
Report the line of a bad row
reader.line_num is the number of physical lines read so far.
import csv
with open('data.csv', newline='', encoding='utf-8') as f:
    rows = csv.reader(f, strict=True)
    try:
        for row in rows:
            pass
    except csv.Error as e:
        print(f'line {rows.line_num}: {e}')

Examples

1. Any iterable of strings works
import csv list(csv.reader(['a,b', '"c,d",e']))
Returns
[['a', 'b'], ['c,d', 'e']]
2. Read a file
import csv with open('p.csv', 'w', newline='') as f: f.write('name,age\r\nAda,36\r\n') with open('p.csv', newline='') as f: rows = list(csv.reader(f)) rows
Returns
[['name', 'age'], ['Ada', '36']]
3. skipinitialspace
import csv line = 'a, b, "c, d"' (next(csv.reader([line])), next(csv.reader([line], skipinitialspace=True)))
Returns
(['a', ' b', ' "c', ' d"'], ['a', 'b', 'c, d'])
4. Escapes instead of quotes
import csv next(csv.reader(['a\\,b,c'], escapechar='\\', quoting=csv.QUOTE_NONE))
Returns
['a,b', 'c']
5. Unquoted fields as floats
import csv next(csv.reader(['1,"2",3.5'], quoting=csv.QUOTE_NONNUMERIC))
Returns
[1.0, '2', 3.5]
6. The dialect it uses
import csv d = csv.reader([], delimiter=';').dialect (d.delimiter, d.quotechar, d.lineterminator)
Returns
(';', '"', '\r\n')
7. A bare \r inside a line
import csv, io list(csv.reader(io.StringIO('a,b\rc,d\n')))
Returns
_csv.Error: new-line character seen in unquoted field - do you need to open the file with newline=''?

Pitfalls

1. Opening the file in binary mode
csv works on str. A file opened with "rb" yields bytes, and the reader refuses them on the first row.
open(path, 'rb')
import csv
with open('p.csv', 'w', newline='') as f:
    f.write('a,b\r\n')
with open('p.csv', 'rb') as f:
    rows = list(csv.reader(f))
_csv.Error: iterator should return strings, not bytes (the file should be opened in text mode)
newline=''
import csv
with open('p.csv', 'w', newline='') as f:
    f.write('a,b\r\n')
with open('p.csv', newline='', encoding='utf-8') as f:
    rows = list(csv.reader(f))
rows
[['a', 'b']]
2. Reading without newline='' changes quoted line breaks
With the default newline=None the file object turns \r\n into \n before the reader sees it, so a multi-line field does not come back as it was written.
open(path)
import csv
with open('q.csv', 'w', newline='') as f:
    csv.writer(f).writerow(['line1\r\nline2'])
with open('q.csv') as f:
    rows = list(csv.reader(f))
rows
[['line1\nline2']]
open(path, newline='')
import csv
with open('q.csv', 'w', newline='') as f:
    csv.writer(f).writerow(['line1\r\nline2'])
with open('q.csv', newline='') as f:
    rows = list(csv.reader(f))
rows
[['line1\r\nline2']]
3. Iterating a reader twice
A reader is a one-pass iterator over the file. The second loop finds it exhausted — keep the rows in a list.
two passes
import csv
rows = csv.reader(['a,b', 'c,d'])
first = list(rows)
second = list(rows)
(len(first), len(second))
(2, 0)
list() once
import csv
rows = list(csv.reader(['a,b', 'c,d']))
(len(rows), len(rows))
(2, 2)

When to use

Use it
  • Row-by-row processing where columns are known by position
  • Large files — the reader streams one row at a time
  • Any delimiter: tabs, semicolons, pipes
Reach for something else
  • Columns by name → csv.DictReader
  • Typed columns and analysis → convert yourself, or pandas.read_csv
  • Fixed-width text → slicing, not csv

Notes

CPython impl
Modules/_csv.c — Reader_iternext feeds each character of each line to parse_process_char, a 9-state machine; errors come from there
Line endings
\n, \r and \r\n all end a row; inside quotes they are kept as data
Field limit
A field longer than csv.field_size_limit() (131072 characters by default) raises csv.Error
Attributes
reader.dialect (the settings in use) and reader.line_num (physical lines read)

FAQ

Call next(reader) once before the loop: header = next(rows). Or use csv.DictReader, which reads the header for you and uses it as the dict keys.