Skip to main content

Files, I/O, and Exception Handling

This page brings together three topics that frequently appear together:

  • How to read input and write output
  • How to handle files safely
  • How to make your program more robust when errors occur

Standard I/O

The most basic input is input():

name = input("name: ")
age = int(input("age: "))
print(name, age)

For multiple values on one line, typically combine split() and map():

x, y = map(int, input().split())

For more complete reading patterns, see this quick reference:

File Reading and Writing

Reading a text file

The most recommended approach is with open(...), which automatically closes the file:

with open("notes.txt", "r", encoding="utf-8") as f:
content = f.read()

Reading line by line

with open("notes.txt", "r", encoding="utf-8") as f:
for line in f:
print(line.rstrip())

Writing to a file

lines = ["alpha", "beta", "gamma"]

with open("out.txt", "w", encoding="utf-8") as f:
f.write("\n".join(lines))

Common modes:

  • "r": Read
  • "w": Write, overwrites existing content
  • "a": Append
  • "rb" / "wb": Binary mode

Basic JSON Handling

For structured data, consider the json module first:

import json

data = {"name": "alice", "score": 95}

with open("data.json", "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)

with open("data.json", "r", encoding="utf-8") as f:
loaded = json.load(f)

Exception Handling

Why handle exceptions

Many errors aren't "code written incorrectly" but rather the runtime environment not meeting expectations:

  • File doesn't exist
  • User input isn't a number
  • Dictionary doesn't have that key
  • Network request failed

Don't pretend the program will never error; instead, explicitly handle the exceptions you expect.

try / except / else / finally

try:
value = int(input("number: "))
except ValueError:
print("Please enter an integer")
else:
print("Read successfully", value)
finally:
print("This part always executes")

Only catch exceptions you actually want to handle

Not recommended to start with:

try:
...
except Exception:
...

This swallows many problems that should be exposed. A safer approach is to write specific exception types first:

try:
with open("missing.txt", "r", encoding="utf-8") as f:
print(f.read())
except FileNotFoundError:
print("File does not exist")

raise: actively raising exceptions

When input doesn't meet your constraints, you can raise an error:

def divide(a, b):
if b == 0:
raise ValueError("b cannot be 0")
return a / b

Habits I recommend

  • Write all file operations as with open(..., encoding="utf-8")
  • Separate "normal logic" and "exception handling" -- don't mix them into one blob
  • Catch as specifically as possible; don't blindly use except Exception
  • When something should fail, let it fail explicitly; don't swallow exceptions just to "look like there's no error"