Files preserve data between program runs, while the with statement ensures that a file is closed correctly even when an error occurs.
Why Do We Need Files?
Data in variables only lives while the program runs. When it closes โ everything is lost.
# Without a file: data disappears when the program closes
score = 100
player = "Rick"
# With a file: data persists between runs
with open("save.txt", "w") as f:
f.write(f"{player}\n{score}\n")
without vs with: Why the Context Manager Matters
# Old way โ easy to forget to close the file
f = open("data.txt", "w")
f.write("Data")
f.close() # If an error occurs before this โ the file won't be closed!
# Correct way โ with closes the file automatically
with open("data.txt", "w") as f:
f.write("Data")
# File is closed here, even if an error occurred inside
Mode “w” โ Write
with open("battle_log.txt", "w") as f:
f.write("=== BATTLE LOG ===\n")
f.write("Rick attacks Walker\n")
f.write("Damage: 20\n")
Note: mode "w" overwrites the file completely on each open.
class Player:
def __init__(self, name):
self.name = name
self.kills = 0
self.health = 100
def save(self):
with open(f"saves/{self.name}.txt", "w") as f:
f.write(f"{self.name}\n")
f.write(f"{self.kills}\n")
f.write(f"{self.health}\n")
print(f"Saved: {self.name}")
player = Player("Rick")
player.kills = 5
player.save()
Mode “r” โ Read
with open("saves/Rick.txt", "r") as f:
content = f.read() # Entire file as a string
print(content)
Reading Methods
with open("saves/Rick.txt", "r") as f:
name = f.readline().strip() # First line
kills = f.readline().strip() # Second line
health = f.readline().strip() # Third line
print(f"{name}: {kills} kills, {health} HP")
with open("battle_log.txt", "r") as f:
lines = f.readlines() # List of lines
for line in lines:
print(line.strip())
strip() removes the \n character at the end of each line.
class Player:
@staticmethod
def load(name):
with open(f"saves/{name}.txt", "r") as f:
loaded_name = f.readline().strip()
kills = int(f.readline().strip())
health = int(f.readline().strip())
p = Player(loaded_name)
p.kills = kills
p.health = health
return p
rick = Player.load("Rick")
print(f"{rick.name}: {rick.kills} kills, {rick.health} HP")
Mode “a” โ Append
Mode "a" adds to the end of the file without deleting existing content:
with open("log.txt", "w") as f:
f.write("Log started\n")
# Later, add events
with open("log.txt", "a") as f:
f.write("Rick killed Walker\n")
with open("log.txt", "a") as f:
f.write("Daryl killed Runner\n")
# File:
# Log started
# Rick killed Walker
# Daryl killed Runner
Mode Table
| Mode | What it does | If file doesn’t exist |
|---|---|---|
"r" |
Reads | Error |
"w" |
Writes (overwrites) | Creates |
"a" |
Appends to end | Creates |
Common Mistakes
Mistake 1: Forgot the Mode
# โ Default is "r" โ can't write
with open("data.txt") as f:
f.write("Data") # UnsupportedOperation: not writable
# โ
Always specify the mode explicitly
with open("data.txt", "w") as f:
f.write("Data")
Mistake 2: File Not Found
# โ File doesn't exist
with open("saves/data.txt", "r") as f:
content = f.read() # FileNotFoundError
# โ
Handle the error
try:
with open("saves/data.txt", "r") as f:
content = f.read()
except FileNotFoundError:
print("File not found โ starting fresh")
content = ""
Custom Context Manager
with works with any object that implements __enter__ and __exit__:
class Timer:
import time
def __enter__(self):
import time
self.start = time.time()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
import time
elapsed = time.time() - self.start
print(f"Elapsed time: {elapsed:.3f}s")
return False # False โ don't suppress exceptions
with Timer():
total = sum(range(1_000_000))
# Elapsed time: 0.031s
__enter__ runs when entering the with block, __exit__ runs on exit (including on error).
๐ฌ Comments (0)
No comments yet
Be the first to share your opinion about this article!