Programs become genuinely useful when they remember things. Files are step one — and Python's with statement makes them nearly impossible to get wrong.
Always use the with statement: with open("file.txt") as f: — it closes the file automatically, even if errors happen. Modes: "r" read (default), "w" write (wipes!), "a" append.
with open("notes.txt", encoding="utf-8") as f:
content = f.read() # whole file as one string
print(content)
with open("notes.txt", encoding="utf-8") as f:
for line in f: # memory-friendly line by line
print(line.strip()) # strip() removes the newlineDanger: mode "w" erases the file the instant it opens. Use "a" to add to the end.
with open("scores.txt", "w", encoding="utf-8") as f:
f.write("Ada: 95\n") # creates or WIPES the file
f.write("Alan: 88\n")
with open("scores.txt", "a", encoding="utf-8") as f:
f.write("Grace: 92\n") # appends — nothing lost# without with — easy to leak the file handle:
f = open("data.txt")
data = f.read()
f.close() # forgotten if an error happens above!
# with — closed automatically, ALWAYS:
with open("data.txt") as f:
data = f.read()
# file is closed here, even after a crashtry:
with open("maybe.txt") as f:
print(f.read())
except FileNotFoundError:
print("No file yet — starting fresh.")
from pathlib import Path
if Path("maybe.txt").exists(): # or check first
print("it's there!")import json
player = {"name": "Ada", "level": 7, "items": ["sword", "map"]}
with open("save.json", "w", encoding="utf-8") as f:
json.dump(player, f, indent=2) # dict → file
with open("save.json", encoding="utf-8") as f:
loaded = json.load(f) # file → dict
print(loaded["items"]) # ['sword', 'map']It guarantees the file is properly closed when the block ends — even if an exception occurs — replacing manual close() calls.
"w" wipes the file and starts fresh; "a" keeps existing content and adds to the end.
Loop directly over the file object: for line in f: — it's memory-efficient even for huge files.
Use the json module: json.dump(data, f) to write, json.load(f) to read it back as a dict.