The Open Modes
The second argument to open() is one or two characters long, and it decides more than any other line in the program. One of these six letters empties the file before you have written anything to it — and there is no way to get the old contents back.
1The mode is a promise
When you open a file you tell Python what you intend to do with it. That is the mode. Python then holds you to it: open for reading and a write() is refused, open for writing and a read() is refused.
f = open('notes.txt', 'r')
f.write('one more line')
f.close()Traceback (most recent call last):
File "held_to_it.py", line 2, in <module>
f.write('one more line')
io.UnsupportedOperation: not writable'r' is a guarantee, checked by Python, that this program cannot damage the file — not by accident, not by a typo in a line you never tested.2Three letters: r, w, a
Everything starts with three. Learn what these do to a file that already has something in it and the rest of the lesson is detail.
'r'Look at the file. You may not change it. If it is not there, the program stops with FileNotFoundError.
'w'Write into the file — after emptying it completely. If it is not there, it is created.
'a'Add to the end of the file. What was there stays. If it is not there, it is created.
Two programs, one letter apart. Run them and read the file after each:
f = open('demo.txt', 'w')
f.write('first line\n')
f.close()
f = open('demo.txt', 'w')
f.write('second line\n')
f.close()
f = open('demo.txt', 'r')
print(f.read())
f.close()second line
f = open('demo.txt', 'a')
f.write('added at the end\n')
f.close()
f = open('demo.txt', 'r')
print(f.read())
f.close()second line added at the end
open('demo.txt', 'w') emptied the file at the moment it was opened — before write() ran, and whether or not it ran at all. A program that opens your notes in 'w' and then crashes on the next line has still destroyed them. This is the single most expensive mistake in the chapter.3And then the + versions
Each of the three has a twin with a + after it. The + means “and the other job too”: a reading mode that may also write, or a writing mode that may also read.
What the + does not change is what happens to the file when it is opened. 'w+' empties the file exactly as 'w' does. 'a+' appends exactly as 'a' does. Read the letter first and the + second.
f = open('demo.txt', 'w')
f.write('Python is easy\n')
f.close()
f = open('demo.txt', 'r+')
f.write('JAVA')
f.close()
f = open('demo.txt', 'r')
print(f.read())
f.close()JAVAon is easy
'r+' opens with the pointer at the start, so those four characters landed on the first four: Pyth became JAVA and on is easy was never touched. Writing into the middle of a file overwrites. Nothing is ever inserted.4Six modes, one file
The same file and the same one-line program, opened six ways. The right-hand pane is the file afterwards — every one of them was run for real.
The same file and the same one-line program, opened six different ways. Watch the right-hand pane.
f.write('JAVA') # io.UnsupportedOperation: not writable
f.close()
Python is easy
Python is easy
The safe one. You may look and nothing else. Writing raises io.UnsupportedOperation: not writable.
5All six, side by side
| Mode | Read? | Write? | If the file is missing | What happens to the contents |
|---|---|---|---|---|
| 'r' | yes | no | FileNotFoundError | kept |
| 'r+' | yes | yes | FileNotFoundError | kept — writes overwrite |
| 'w' | no | yes | created | ERASED |
| 'w+' | yes | yes | created | ERASED |
| 'a' | no | yes | created | kept — writes go to the end |
| 'a+' | yes | yes | created | kept — writes go to the end |
6Where each mode leaves the pointer
An open file has a pointer — the place the next read or write will happen. The mode decides where it starts, and that is the difference between 'r+' and 'a+', which otherwise look alike.
Position 0. For 'w' and 'w+' the file is empty by then anyway, so the start is also the end.
Straight past everything already in the file, which is exactly why an append can never overwrite anything.
That has one consequence worth seeing, because it catches everyone: open a file in 'a+' and read it immediately, and you get an empty string. There is nothing after the pointer.
f = open('demo.txt', 'w')
f.write('line one\n')
f.close()
f = open('demo.txt', 'a+')
print('read gives:', repr(f.read()))
f.close()
f = open('demo.txt', 'r')
print('but the file holds:', repr(f.read()))
f.close()read gives: '' but the file holds: 'line one\n'
'a+' handle simply had nothing in front of it to read. Sending the pointer back to the start without opening the file again is what seek() is for, and it has a lesson later in this chapter.7The letter you never see: t
There is a second half to every mode. 'r' is really 'rt' — read, in text mode. Text mode is the default, so nobody writes the t.
Swap it for 'b' and you are in binary mode: 'rb', 'wb', 'ab'. That is how a program opens a photo or a .docx — the files the last chapter called binary. In binary mode you read and write bytes rather than strings.
| Text mode ('t', the default) | Binary mode ('b') | |
|---|---|---|
| You read and write | str — ordinary strings | bytes |
| Line endings | Translated for your OS | Left exactly as they are |
| Used for | .txt .py .csv .html | .png .pdf .docx .mp3 |
| Written as | 'r', 'w', 'a' (the t is assumed) | 'rb', 'wb', 'ab' |
'rb' in a question paper, now you know it is the same six modes with one letter added.8Choosing, in one question
Ask what should happen to what is already in the file. The answer names the mode:
'r'The safest choice, and it is the default for a reason.
'w'A report generated afresh every run. Nothing worth keeping is in there.
'a'Logs, attendance, anything that grows. This is the one real programs use most.
'r+'Rare, and easy to get wrong — writes overwrite from wherever the pointer is.
Try it yourself. Change the mode on the first line, run it, and watch what the file ends up holding:
9Recap
A string. Leave it out and Python uses 'r'.
Three letters, and the whole table follows from them.
Reading to a writing mode, writing to a reading mode. It never changes what happens to the file.
r and r+ do not — they raise FileNotFoundError instead.
In 'r+' the new characters land on top of the old ones from wherever the pointer is.
'rb', 'wb', 'ab' read and write bytes. Without it you are in text mode, which is all of this chapter.
- 1
Write three lines into
diary.txtwith'w'. Run the program a second time. How many lines are in the file?Hint · Three. Not six — and that is the point of the exercise.
- 2
Change the mode to
'a'and run it twice more.Hint · Now it grows by three lines every run.
- 3
Open a file that does not exist in
'w', then open another that does not exist in'r'.Hint · One creates a file. The other raises FileNotFoundError.
- 4
Put
Hello worldin a file, open it in'r+', writeHELP, and read the file.Hint · HELPo world. Four characters replaced, none inserted.
A file holds three lines. You open it with mode 'w' and the program crashes before write() runs. What is in the file?
Which mode adds to a file, and creates it if it is not there?
demo.txt holds 'Python is easy'. You open it in 'r+' and write 'JAVA' straight away. What does the file hold now?
What does the + in 'w+' change?
You open a file in 'a+' and call read() immediately. What comes back?