reader()
Writing had two calls; reading has one. Wrap the open file in csv.reader() and loop over it, and each line of the file arrives as a list — already split, with the quoting sorted out. There is exactly one thing it does not do for you, and it costs marks every year.
1csv.reader() — wrapping the file
r = csv.reader(file)One argument — the file open() gave you, in 'r'. What comes back is the reader.
Reading marks.csv, the file written in the last two lessons:
import csv
f = open('marks.csv', 'r', newline='')
r = csv.reader(f)
for row in r:
print(row)
f.close()['Roll', 'Name', 'Marks'] ['1', 'Ravi', '78'] ['2', 'Meera', '91'] ['3', 'Amit', '65']
r = csv.reader(f)Wraps the file. Nothing is read yet — this line alone prints nothing and moves no pointer.
for row in r:The loop is what reads. Each turn brings back the next line of the file, already split into a list.
print(row)row is an ordinary Python list, so row[0], len(row) and slicing all work exactly as you would expect.
for row in csv.reader(f): — and most board answers do. The two-line version is easier to read while you are learning, and neither is wrong.2Every value comes back as a string
Look at that output again. The marks are '78', not 78. They were written as numbers, and they have come back as text:
import csv
f = open('marks.csv', 'r', newline='')
r = csv.reader(f)
next(r)
for row in r:
print(row[2], type(row[2]))
print(row[2] + 10)
f.close()78 <class 'str'>
Traceback (most recent call last):
File "strings.py", line 9, in <module>
print(row[2] + 10)
TypeError: can only concatenate str (not "int") to str78 was ever a number. Anything you want to do arithmetic with needs int() or float() first. This is not a quirk of the csv module — it is the same rule as input(), and the same rule as reading a text file.import csv
f = open('marks.csv', 'r', newline='')
r = csv.reader(f)
header = next(r)
total = 0
for row in r:
total = total + int(row[2])
f.close()
print('Header was:', header)
print('Total marks:', total)Header was: ['Roll', 'Name', 'Marks'] Total marks: 234
3Skipping the header — and what next() actually does
The reader hands back every line, and the first one is usually the header. Try to add it in with the marks and you get ValueError: invalid literal for int() with base 10: 'Marks'. The usual way past it is a built-in function called next(), and it is worth understanding rather than copying, because it is not really a “skip” instruction at all.
next(r)Reads exactly one row, moves the pointer past it, and returns that row.
Two things happen on every call, and they are separate. It reads a row — that is a change to where the file pointer is sitting. And it gives that row back — that is a value, which you may catch or may not.
import csv
f = open('marks.csv', 'r', newline='')
r = csv.reader(f)
first = next(r)
print(first)
print(type(first))
f.close()['Roll', 'Name', 'Marks'] <class 'list'>
A list, exactly like the ones the loop gives you — because it is the same row, fetched the same way. Call it again and you get the one after it, because the pointer moved:
import csv
f = open('marks.csv', 'r', newline='')
r = csv.reader(f)
print(next(r))
print(next(r))
print(next(r))
f.close()['Roll', 'Name', 'Marks'] ['1', 'Ravi', '78'] ['2', 'Meera', '91']
for row in r: has been doing all along — calling next() once per turn and putting the answer in row. That is the whole reason a next() before the loop shifts the loop's starting point: the row has already been taken, so the loop begins at the one after it.4Skipping is just ignoring the answer
Here is the part that confuses people. There is no “skip” function in Python. To skip a row you use the reading half of next() and simply do not keep what it hands back:
import csv
f = open('marks.csv', 'r', newline='')
r = csv.reader(f)
next(r) # read it, keep nothing
for row in r:
print(row)
f.close()['1', 'Ravi', '78'] ['2', 'Meera', '91'] ['3', 'Amit', '65']
next(r) sits on a line by itself, with no = in front of it. Python runs it, the header is read, and the list it returns is thrown away because nothing was waiting to catch it. The header never reaches the loop. It was not deleted — it was read past.
header = next(r) print(header[1]) # Name
Useful when you print a heading above the table, as the practice page does.
next(r)
Same reading, same pointer move. The only difference is that nobody caught the answer.
header = next(r) and never using header is not a mistake — it costs one unused variable and nothing else. Marks are given for either.5Skipping more than one row
One call, one row. Two rows to get rid of means two calls — there is nothing to add and no count to pass:
import csv
f = open('marks.csv', 'r', newline='')
r = csv.reader(f)
next(r) # the header
next(r) # and Ravi's row as well
for row in r:
print(row)
f.close()['2', 'Meera', '91'] ['3', 'Amit', '65']
The same idea works anywhere, not only at the top of the file. A next(r) in the middle of a loop reads one extra row and drops it, so the loop skips it.
6Two things to watch
next(r) reads past the first line whatever it is. On a file with no header row it quietly swallows your first record, and your count comes out one short. Look at the file before you write the loop.And next() needs a row to be there. Ask for one when the file is finished and it does not return an empty list — it raises:
import csv
f = open('marks.csv', 'r', newline='')
r = csv.reader(f)
next(r)
next(r)
next(r)
next(r)
next(r)Traceback (most recent call last):
File "next_too_far.py", line 10, in <module>
next(r)
StopIterationFour rows in the file, so four calls work and the fifth has nothing left. StopIteration is the signal a for loop catches for you — it is how the loop knows to stop. Called by hand, nobody catches it, so it reaches the screen. In practice this only bites on an empty file, where there is not even a header to skip.
7The other way you will see it written
Some answers skip the header with a counter instead. It works, it is longer, and it is worth recognising in someone else's code:
import csv
f = open('marks.csv', 'r', newline='')
r = csv.reader(f)
n = 0
for row in r:
n = n + 1
if n == 1:
continue
print(row)
f.close()['1', 'Ravi', '78'] ['2', 'Meera', '91'] ['3', 'Amit', '65']
Five lines doing what next(r) does in one. Use next().
8A reader can only be looped once
The loop moves the file pointer to the end. Loop a second time and there is nothing left in front of it:
import csv
f = open('marks.csv', 'r', newline='')
r = csv.reader(f)
print('first loop:')
for row in r:
print(row)
print('second loop:')
for row in r:
print(row)
print('done')
f.close()first loop: ['Roll', 'Name', 'Marks'] ['1', 'Ravi', '78'] ['2', 'Meera', '91'] ['3', 'Amit', '65'] second loop: done
No error — the second loop simply runs zero times. This is the exact behaviour read() had in the Text Files chapter, and the repair is the same one: send the pointer back with seek(0).
import csv
f = open('marks.csv', 'r', newline='')
r = csv.reader(f)
for row in r:
print(row)
f.seek(0)
print('--- again ---')
for row in r:
print(row)
f.close()['Roll', 'Name', 'Marks'] ['1', 'Ravi', '78'] ['2', 'Meera', '91'] ['3', 'Amit', '65'] --- again --- ['Roll', 'Name', 'Marks'] ['1', 'Ravi', '78'] ['2', 'Meera', '91'] ['3', 'Amit', '65']
rows = list(csv.reader(f)). A list can be looped as often as you like, and every update and delete program in this chapter is built on exactly that line.import csv
f = open('marks.csv', 'r', newline='')
data = list(csv.reader(f))
f.close()
print(data)
print(len(data))
print(data[2][1])[['Roll', 'Name', 'Marks'], ['1', 'Ravi', '78'], ['2', 'Meera', '91'], ['3', 'Amit', '65']] 4 Meera
Note len(data) is 4, not 3 — the header is one of the rows. Counting records means subtracting it, or skipping it before you count.
9Read a file you wrote yourself
10Reading and writing, side by side
| csv.writer(f) | csv.reader(f) | |
|---|---|---|
| File mode | 'w' or 'a' | 'r' |
| What you give it | the open file | the open file |
| How you use it | w.writerow(row) / w.writerows(rows) | for row in r: |
| Direction | list → line | line → list |
| Values | numbers accepted as they are | everything comes back as str |
| Reusable | call writerow() as often as you like | one loop only, unless you seek(0) |
11Recap
Wraps the open file. Reads nothing by itself — the loop is what reads.
Already split on the commas, with any quoting removed. row[0], len(row) and slicing all work.
'78', not 78. int() before any arithmetic, or you get TypeError.
Two separate things: the pointer moves past that row, and the row is handed back. A for loop is next() called once per turn.
next(r) on a line of its own reads the header and throws the value away. It was not deleted, just read past. Two rows to skip means two calls.
StopIteration — the signal a for loop catches for you. Only bites on an empty file, where there is no header to skip.
The second loop runs zero times. f.seek(0) sends the pointer back to the start.
All the rows in a list, loopable as often as you like — and the header is one of them, so len() is one more than you expect.
- 1
Print only the names from a CSV of student records.
Hint · row[1], once you have skipped the header with next().
- 2
Add up a column of marks, first without
int()and then with it.Hint · Without it you get either a
TypeErroror a very long string, depending on how you started the total. - 3
Put
next(r)in a variable and print it, then run the same program with the variable taken away.Hint · The loop starts at the same row either way. Catching the answer changes nothing about the skipping.
- 4
Call
next(r)one more time than the file has rows.Hint · StopIteration. There was nothing left to read.
- 5
Loop over the same reader twice and count what you get.
Hint · Four rows, then none. Add f.seek(0) between them.
- 6
Read the file into a list and print
len()— then work out how many records that is.Hint · One fewer than the length. The header is a row too.
What type is each row that csv.reader() hands back?
row[2] holds '78'. What does row[2] + 10 do?
What does next(r) do?
Why does writing next(r) on a line by itself skip a row?
A file has a header and you want to skip the header AND the first record. What do you write?
You loop over a reader, then loop over it again. What does the second loop print?