Everything so far vanished
Every value you have made lived in memory and disappeared the moment the program ended. Files are how a program keeps something.
with open("notes.txt", "w", encoding="utf-8") as f:
f.write("first line\n")
f.write("second line\n")Run that and a file called notes.txt appears next to your script. Three parts of that line matter.
The mode. "w" means write. "r" means read, and is the default if you leave it out. "a" means append.
`encoding="utf-8"`. This says how characters are turned into bytes. Leave it out and Python uses whatever your operating system prefers, which differs between machines and will mangle any text that is not plain English. Always pass it. It costs you nothing and saves a whole class of bug involving names, accents and scripts that are not Latin.
`with`. A file has to be closed, or your writes may sit in a buffer and never reach the disk. with closes it for you when the indented block ends, including when an error is thrown inside. Use with and stop thinking about it.
Writing empties the file first
with open("notes.txt", "w", encoding="utf-8") as f:
f.write("only this\n")Run that twice and the file still contains one line. Mode "w" truncates: it empties the file before the first write. It does this even if you never write anything. To add without destroying, use "a":
with open("notes.txt", "a", encoding="utf-8") as f:
f.write("added later\n")Also: write does not add a line break. If you want lines, put \n yourself.
Reading
with open("notes.txt", encoding="utf-8") as f:
text = f.read()
print(text)
print(len(text))read() gives the whole file as one string. Fine for something small, wasteful for a large log. To go line by line, loop over the file itself:
with open("notes.txt", encoding="utf-8") as f:
for line in f:
print(line.strip())Each line still carries its \n at the end, which is why .strip() is there. Without it, print adds a second break and everything looks double spaced.
Where is the file
FileNotFoundError: [Errno 2] No such file or directory: 'notes.txt'A plain filename is relative to the folder your terminal is in when you run the command, not the folder the script is saved in. Those are often different. Check with pwd on macOS or Linux, cd on Windows, or from inside Python:
import os
print(os.getcwd())JSON, for structured data
Text files are fine for lines of prose. When you want to save a dict or a list, use JSON: a text format that most of the world's software, including every AI API, agrees on.
import json
data = {"name": "Amara", "city": "Kano", "marks": [78, 81, 92]}
with open("student.json", "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
with open("student.json", encoding="utf-8") as f:
back = json.load(f)
print(type(back)) # <class 'dict'>
print(back["marks"][1]) # 81json.dump writes a dict to a file. json.load reads it back as a real dict. ensure_ascii=False keeps non-English characters readable in the file instead of turning them into escape codes. indent=2 makes it pleasant for a human to open.
The two you will use in lesson ten are the string versions: json.dumps(data) turns a dict into a string, json.loads(text) turns a string back into a dict. That is exactly what travels over the internet when you call an API.
Try this now
with open("log.txt", "a", encoding="utf-8") as f:
f.write("ran once\n")
with open("log.txt", encoding="utf-8") as f:
lines = f.readlines()
print(f"{len(lines)} runs so far")Run it four times.
Before you move on