Reading and Writing Files
Save and load data that outlives your program
In this lesson
Reading and writing files is how a Python program saves data that outlives a single run — because variables vanish when your program ends. This lesson covers reading from and writing to text files, the foundation of saving and loading information.
Explain it like I’m 5
A file is a notebook on disk. Your program can open it to read what’s written, or open it to write new things down — and unlike a variable, what’s in the notebook is still there tomorrow.
Opening files with with
The right way to open a file is the with statement: with open("notes.txt") as f:. The with block automatically closes the file when you’re done — even if an error occurs — so you never leak open files. Always use with; manually calling open() and close() is error-prone.
# Run this locally — it creates a file on your computer.
with open("notes.txt", "w") as f:
f.write("Saved from Python!\n")
# Outside the block, the file is already closed for you.
print("File written and closed.")
File written and closed.
Read modes and write modes
The second argument to open is the mode: "r" read (the default), "w" write (creates the file, or erases existing contents), "a" append (adds to the end without erasing). Choosing the wrong mode is a classic mistake — "w" will silently wipe a file you meant only to read.
# "a" adds to the end without erasing what's there.
with open("log.txt", "a") as f:
f.write("ran the report\n")
print("Appended one line to the log.")
Appended one line to the log.
Reading text
# Assume greetings.txt contains two lines: Hello and World.
with open("greetings.txt", "r") as f:
for line in f:
print(line.strip())
Hello World
Writing text
Open with "w" or "a" and call f.write("some text"). Unlike print, write does not add a newline, so include \n yourself when you want line breaks. Everything you write is text; convert numbers with str() first.
# Numbers must be turned into text before writing.
with open("scores.txt", "w") as f:
for n in [90, 75, 88]:
f.write(str(n) + "\n")
print("Wrote 3 scores, one per line.")
Wrote 3 scores, one per line.
Encoding, and structured formats (JSON, CSV)
Two practical notes for real-world files. First, encoding: open text files with encoding="utf-8" so accented letters and emoji read correctly everywhere — open("notes.txt", encoding="utf-8"). Leaving it out can give different results on different machines.
Second, you rarely invent your own file format. The standard library’s json module handles nested data and csv handles spreadsheet rows — both via import. The example below uses json without touching a file, so it runs right here; to actually save the result, write the text to a file as shown earlier (and find it with pathlib).
import json
data = {"name": "Ada", "topics": ["loops", "lists"]}
text = json.dumps(data)
print(text)
restored = json.loads(text)
print(restored["topics"])
{"name": "Ada", "topics": ["loops", "lists"]}
['loops', 'lists']
Common mistake: Forgetting to use with (and leaving files open)
Calling open() without with means you must remember to close() — and if an error happens first, the file stays open.
Always use with open(...) as f:. The file closes automatically at the end of the block, even on errors.
with open("data.txt") as f:
contents = f.read()
# file is closed here automatically
Common mistake: Opening with "w" when you meant to read
"w" looks harmless but truncates the file to empty before you do anything.
Use "r" (or omit the mode) to read. Reserve "w" for when you intend to replace the file’s contents.
Why use 'with' when opening a file?
The with statement guarantees the file is closed when the block ends, avoiding leaked file handles.
Which mode ERASES an existing file's contents when opened?
Opening with "w" truncates the file; "a" adds to it and "r" only reads.
Mini exercise (medium)
Locally, write the numbers 1 to 5 to numbers.txt, one per line, then read the file back and print the total of all the numbers.
Real files need your own computer, so here we keep the text in memory — the read-back-and-total logic is identical. Build the lines, then total the numbers.
# Build the "file" text: numbers 1..5, one per line
text = "\n".join(str(n) for n in range(1, 6))
# Now read it back and total the numbers:
total = 0
for line in text.splitlines():
pass # TODO: add int(line) to total
print(total)
Write with f.write(str(n) + "\n") in a loop; when reading, convert each line with int(line) and add to a running total.
text = "\n".join(str(n) for n in range(1, 6))
total = 0
for line in text.splitlines():
total += int(line)
print(total)
assert total == 15, "1 plus 2 plus 3 plus 4 plus 5 is 15"
print("✓ Correct!")