Choosing the Separator
The C in CSV stands for comma, and it has misled a great many students. The comma is what the csv module uses when you do not say otherwise — a default, not a rule. Any single character can be the separator, and one argument is how you pick it.
1The delimiter argument
csv.writer(f, delimiter='|')Goes after the file, on csv.writer() and csv.reader() alike. Leave it out and you get ','.
import csv
f = open('marks_pipe.csv', 'w', newline='')
w = csv.writer(f, delimiter='|')
w.writerow(['Roll', 'Name', 'Marks'])
w.writerow([1, 'Ravi', 78])
w.writerow([2, 'Meera', 91])
f.close()
print(open('marks_pipe.csv', newline='').read())Roll|Name|Marks 1|Ravi|78 2|Meera|91
Nothing else about the program changed. The rows are the same lists, the methods are the same methods — only the character between the values is different.
2Why anyone would want a different one
Much of Europe writes twelve and a half rupees as 12,50. A comma is already the decimal point there, so it cannot also be the separator. Open a European CSV in Excel and it is almost always semicolons.
Almost never appears inside real data, so no value ever needs quoting. Common when the values are addresses or sentences.
Gives you a TSV file. The columns line up when you open it in a plain editor, which makes it much easier to read by eye.
A colon, a hash, a space. If it is one character, the module will use it — though your reader has to know.
The semicolon case is the one worth seeing, because the file would be unreadable any other way:
import csv
f = open('euro.csv', 'w', newline='')
w = csv.writer(f, delimiter=';')
w.writerow(['Item', 'Price'])
w.writerow(['Pen', '12,50'])
f.close()
print(open('euro.csv', newline='').read())
f = open('euro.csv', 'r', newline='')
for row in csv.reader(f, delimiter=';'):
print(row)
f.close()Item;Price Pen;12,50 ['Item', 'Price'] ['Pen', '12,50']
The comma inside 12,50 is left completely alone, because on this file a comma is not a separator — a semicolon is.
3Both sides have to be told
The delimiter is not written down anywhere in the file. There is no header saying “this file uses pipes” — there are just characters. So the reader has to be told the same thing the writer was told. Here is the pipe file from section 1, read with the default:
import csv
f = open('marks_pipe.csv', 'r', newline='')
for row in csv.reader(f):
print(row)
f.close()['Roll|Name|Marks'] ['1|Ravi|78'] ['2|Meera|91']
row[0] is the whole line and row[1] raises IndexError: list index out of range somewhere further down. When a CSV reads back as one long string per row, this is the first thing to check.Told the right separator, the same file reads perfectly:
import csv
f = open('marks_pipe.csv', 'r', newline='')
for row in csv.reader(f, delimiter='|'):
print(row)
f.close()['Roll', 'Name', 'Marks'] ['1', 'Ravi', '78'] ['2', 'Meera', '91']
csv.reader(f, delimiter='|')The same argument, in the same position, on the reader. Whatever the writer was told, the reader must be told too.
the file did not changeBoth runs above read the identical file off the disk. Only the instruction differed — which is what makes the delimiter a setting rather than part of the data.
4Set both knobs yourself
Set the separator the writer uses, then set the one the reader is told to expect. They do not have to agree — and nothing warns you when they do not.
w = csv.writer(f, delimiter='|')for row in csv.reader(f):They disagree. The reader hunted for commas, found none, and handed back the whole line as a single value. No error, no warning — just row[1] raising IndexError somewhere further down your program.
5Exactly one character
A separator is a single character. Two is not allowed, and this one does stop the program:
import csv
f = open('x.csv', 'w', newline='')
w = csv.writer(f, delimiter='||')Traceback (most recent call last):
File "two_chars.py", line 4, in <module>
w = csv.writer(f, delimiter='||')
TypeError: "delimiter" must be a 1-character string'\t' is fine, because a tab is one character — the backslash and the t are how you type it, not what it is. The same goes for any escape sequence.6Quoting follows whichever character you chose
The writer quotes a value when that value contains the separator. Change the separator and you change which values need quoting — the same row, written twice:
import csv
row = ['Sharma, Kumar and Sons', 'Delhi']
f = open('shops1.csv', 'w', newline='')
csv.writer(f).writerow(row)
f.close()
f = open('shops2.csv', 'w', newline='')
csv.writer(f, delimiter='|').writerow(row)
f.close()
print(open('shops1.csv', newline='').read())
print(open('shops2.csv', newline='').read())"Sharma, Kumar and Sons",Delhi Sharma, Kumar and Sons|Delhi
With commas separating, the name needed quotes. With pipes separating, the comma inside the name is just an ordinary character and no quotes were needed. Either file reads back as the same two values — provided the reader is told which separator was used.
7It is still called a CSV file
A file separated by semicolons is still a CSV file, and is still normally named .csv. The name stopped being literal a long time ago — people use it for the whole family of “one record per line, values separated by something” files. Tab-separated files are the one common exception: those are often named .tsv instead.
8Try every separator on one file
9Recap
| What happens | |
|---|---|
| delimiter left out | the comma is used — that is the default |
| delimiter='|' on both sides | the file uses pipes and reads back correctly |
| delimiter='|' on the writer only | each row reads back as one long value, with no error |
| delimiter='||' | TypeError: "delimiter" must be a 1-character string |
| delimiter='\t' | a tab — one character, so perfectly legal. Usually named .tsv |
| a value containing the separator | the writer wraps that value in quotes automatically |
Not part of the format. csv.writer(f) and csv.writer(f, delimiter=',') are the same call.
Semicolon, pipe, tab, colon. Two characters raises TypeError.
Nothing in a CSV says which separator it uses. You have to know, or look at the file.
The commonest mistake. A mismatch gives no error — just one value per row.
Where the comma is the decimal point, or where the values themselves are full of commas.
The extension does not change with the separator. Tab-separated files are often .tsv.
- 1
Write the same three rows four times, with
',',';','|'and'\t', and open all four in Notepad.Hint · Same values, four different-looking files.
- 2
Write with a semicolon and read with the default. Count the values in each row.
Hint · One. And Python said nothing at all.
- 3
Try
delimiter='::'and read the error.Hint · Must be a 1-character string.
- 4
Write a value containing a pipe into a pipe-separated file, then open the file.
Hint · Quotes. The rule follows whichever separator you chose.
What separator does csv.writer(f) use when you do not say?
You wrote a file with delimiter='|' and read it back with csv.reader(f). What happens?
Why do many European CSV files use semicolons?
Is delimiter='||' allowed?