Error Handling & Files
Managing errors and working with file systems
Error Handling & Files in Python
Master Python error handling and file operations with free flashcards and spaced repetition practice. This lesson covers exception handling with try-except blocks, working with different file modes, and best practices for reading and writing dataβessential concepts for building robust Python applications.
π» Welcome to one of Python's most practical topics! Every program encounters errors, and every useful application needs to save or load data. By mastering error handling and file operations, you'll write code that doesn't crash when things go wrong and can persist data beyond a single program run.
Core Concepts
π‘οΈ Exception Handling: The Basics
In Python, errors that occur during execution are called exceptions. Without proper handling, exceptions cause your program to crash. The try-except block lets you catch and handle these errors gracefully.
Basic Structure:
try:
# Code that might raise an exception
risky_operation()
except ExceptionType:
# Code that runs if exception occurs
handle_error()
π‘ Think of try-except like a safety net: You attempt something risky in the try block, and if it fails, the except block catches you before you hit the ground.
π Common Python Exceptions
| Exception Type | When It Occurs | Example |
|---|---|---|
| ValueError | Invalid value for operation | int("hello") |
| TypeError | Operation on wrong type | "5" + 5 |
| FileNotFoundError | File doesn't exist | open("missing.txt") |
| ZeroDivisionError | Division by zero | 10 / 0 |
| KeyError | Dictionary key not found | dict["nonexistent"] |
| IndexError | List index out of range | list[99] |
π― Multiple Exception Handling
You can catch different exceptions and handle them differently:
try:
value = int(input("Enter a number: "))
result = 100 / value
except ValueError:
print("That's not a valid number!")
except ZeroDivisionError:
print("Cannot divide by zero!")
except Exception as e:
print(f"Unexpected error: {e}")
The order matters! Python checks exceptions from top to bottom, so put specific exceptions before general ones.
π§ Memory device - VEST: ValueError, Exception (general), Specific first, Then general
π The Complete Try-Except Structure
Python offers four clauses for comprehensive error handling:
try:
β Attempt risky code
risk_operation()
except ExceptionType:
β Handle specific error
handle_error()
else:
β Runs if NO exception occurred
success_actions()
finally:
β ALWAYS runs (cleanup)
cleanup_resources()
Key points:
- try: Required - contains code that might fail
- except: Required - handles the exception
- else: Optional - runs only if try succeeds
- finally: Optional - runs no matter what (perfect for cleanup)
try:
file = open("data.txt", "r")
content = file.read()
except FileNotFoundError:
print("File not found!")
else:
print("File read successfully!")
finally:
file.close() # Always close the file
π Raising Exceptions
You can raise exceptions intentionally to signal errors in your own code:
def set_age(age):
if age < 0:
raise ValueError("Age cannot be negative!")
if age > 150:
raise ValueError("Age seems unrealistic!")
return age
π‘ Best practice: Raise exceptions early to fail fast and make debugging easier.
π File Operations: Opening and Closing Files
Python's open() function creates a file object for reading or writing. The most important parameter is the mode:
| Mode | Description | Creates New File? | Overwrites? |
|---|---|---|---|
| "r" | Read (default) | No - error if missing | N/A |
| "w" | Write | Yes | YES - deletes content! |
| "a" | Append | Yes | No - adds to end |
| "r+" | Read and Write | No - error if missing | No |
| "x" | Exclusive create | Yes - error if exists | N/A |
β οΈ WARNING: Mode "w" will erase all existing content immediately upon opening! Use "a" to preserve existing data.
Add "b" for binary mode (e.g., "rb", "wb") when working with images, videos, or other non-text files.
π The "with" Statement (Context Manager)
The with statement automatically handles file closing, even if errors occur:
with open("data.txt", "r") as file:
content = file.read()
# File automatically closes after this block
Why use "with"?
- β Automatically closes files (no memory leaks)
- β Closes even if exception occurs
- β Cleaner, more readable code
- β
No need to remember
file.close()
π§ Memory device - WAS: With Auto Shuts (files)
π Reading Files: Three Methods
| Method | Returns | Best For |
|---|---|---|
| read() | Entire file as one string | Small files |
| readline() | Single line (with \n) | Processing line by line |
| readlines() | List of all lines | When you need all lines as list |
# Method 1: Read entire file
with open("story.txt", "r") as file:
content = file.read()
print(content)
# Method 2: Read line by line (memory efficient)
with open("story.txt", "r") as file:
for line in file: # Iterates naturally
print(line.strip()) # strip() removes \n
# Method 3: Read all lines into list
with open("story.txt", "r") as file:
lines = file.readlines()
print(lines[0]) # Access first line
π‘ Pro tip: For large files, iterate directly over the file object (for line in file) instead of using readlines() - it's more memory efficient!
βοΈ Writing Files: Two Methods
# write() - writes a string
with open("output.txt", "w") as file:
file.write("Hello, World!\n")
file.write("Second line\n")
# writelines() - writes list of strings
lines = ["First line\n", "Second line\n", "Third line\n"]
with open("output.txt", "w") as file:
file.writelines(lines)
β οΈ Important: write() and writelines() don't add newlines automatically - you must include \n yourself!
π File Existence Checking
Before opening a file, you might want to check if it exists:
import os
if os.path.exists("data.txt"):
with open("data.txt", "r") as file:
content = file.read()
else:
print("File not found!")
Or use exception handling:
try:
with open("data.txt", "r") as file:
content = file.read()
except FileNotFoundError:
print("File not found!")
π‘ Python philosophy: "It's Easier to Ask Forgiveness than Permission" (EAFP) - use try-except rather than checking first.
π‘ Practical Examples
Example 1: Safe Number Input with Error Handling
def get_number():
"""Get a valid number from user with error handling"""
while True:
try:
value = float(input("Enter a number: "))
return value
except ValueError:
print("Invalid input! Please enter a number.")
except KeyboardInterrupt:
print("\nOperation cancelled by user.")
return None
# Usage
num = get_number()
if num is not None:
print(f"You entered: {num}")
Why this works:
- The
while Trueloop continues until valid input is received ValueErrorcatches non-numeric inputKeyboardInterruptcatches Ctrl+C gracefully- Returns
Noneon cancel, allowing calling code to handle it
Example 2: Reading and Processing a CSV-like File
def read_student_scores(filename):
"""Read student scores and calculate average"""
try:
with open(filename, "r") as file:
students = {}
for line in file:
name, score = line.strip().split(",")
students[name] = float(score)
return students
except FileNotFoundError:
print(f"Error: {filename} not found!")
return {}
except ValueError:
print("Error: Invalid data format in file!")
return {}
# Usage
scores = read_student_scores("scores.txt")
if scores:
average = sum(scores.values()) / len(scores)
print(f"Class average: {average:.2f}")
Key techniques:
- Uses
withfor automatic file closing strip()removes whitespace and newlinessplit(",")separates name and score- Multiple except blocks handle different errors
- Returns empty dict on error (safe default)
Example 3: Logging Program Events to File
import datetime
def log_event(message, log_file="program.log"):
"""Append timestamped message to log file"""
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
log_entry = f"[{timestamp}] {message}\n"
try:
with open(log_file, "a") as file: # "a" = append mode
file.write(log_entry)
except PermissionError:
print(f"Error: No permission to write to {log_file}")
except Exception as e:
print(f"Unexpected error: {e}")
# Usage
log_event("Program started")
log_event("User logged in")
log_event("Error occurred in module X")
log_event("Program ended")
Important features:
- Append mode (
"a") preserves existing logs - Timestamps make logs useful for debugging
- Catches
PermissionError(common in protected directories) - Generic
Exceptioncatches unexpected errors
Example 4: Configuration File Reader with Defaults
def load_config(filename="config.txt"):
"""Load configuration with fallback defaults"""
# Default configuration
config = {
"username": "guest",
"theme": "light",
"max_connections": 10
}
try:
with open(filename, "r") as file:
for line in file:
if "=" in line and not line.startswith("#"):
key, value = line.strip().split("=", 1)
config[key.strip()] = value.strip()
print(f"Configuration loaded from {filename}")
except FileNotFoundError:
print(f"Config file not found, using defaults")
except Exception as e:
print(f"Error reading config: {e}, using defaults")
finally:
return config
# Usage
settings = load_config()
print(f"Theme: {settings['theme']}")
print(f"Max connections: {settings['max_connections']}")
Design patterns:
- Provides sensible defaults (graceful degradation)
- Skips comment lines (starting with
#) split("=", 1)splits only on first=(handles values with=)finallyensures config is always returned- Robust against missing or malformed files
π§ Try this: Create a config.txt file with contents:
username=john
theme=dark
# This is a comment
max_connections=25
Run the code and observe how it overrides defaults!
β οΈ Common Mistakes
Mistake 1: Forgetting to Close Files
β Wrong:
file = open("data.txt", "r")
content = file.read()
# Forgot file.close() - resource leak!
β Right:
with open("data.txt", "r") as file:
content = file.read()
# Automatically closed
Mistake 2: Catching Exception Too Broadly Too Early
β Wrong:
try:
value = int(input())
result = 100 / value
except Exception: # Too broad!
print("Something went wrong")
# Can't tell if ValueError or ZeroDivisionError
β Right:
try:
value = int(input())
result = 100 / value
except ValueError:
print("Invalid number format")
except ZeroDivisionError:
print("Cannot divide by zero")
Mistake 3: Using "w" Mode When You Mean "a"
β Wrong:
with open("log.txt", "w") as file: # ERASES entire file!
file.write("New log entry\n")
β Right:
with open("log.txt", "a") as file: # Appends to end
file.write("New log entry\n")
Mistake 4: Not Handling File Encoding
β Wrong:
with open("unicode_file.txt", "r") as file:
content = file.read() # May fail on special characters
β Right:
with open("unicode_file.txt", "r", encoding="utf-8") as file:
content = file.read() # Handles international characters
Mistake 5: Catching but Not Handling
β Wrong:
try:
risky_operation()
except Exception:
pass # Silent failure - very bad!
β Right:
try:
risky_operation()
except Exception as e:
print(f"Error occurred: {e}")
# Or log it, or handle appropriately
π€ Did you know? The pass statement in an except block is called "swallowing exceptions" and is considered a code smell. It hides bugs and makes debugging nearly impossible!
π― Key Takeaways
β Use try-except blocks to handle errors gracefully instead of crashing
β Always use "with" statement for file operations - it handles closing automatically
β Catch specific exceptions first, then more general ones
β "w" mode erases files, use "a" to append, "r+" to read and write
β The finally block always executes - perfect for cleanup operations
β Raise exceptions in your own code when something goes wrong
β Iterate over file objects directly for memory-efficient line-by-line reading
β Specify encoding="utf-8" when working with international text
π Further Study
Python Official Documentation - Errors and Exceptions: https://docs.python.org/3/tutorial/errors.html - Comprehensive guide to Python's exception handling
Real Python - Reading and Writing Files: https://realpython.com/read-write-files-python/ - In-depth tutorial with advanced techniques
Python Official Documentation - File Objects: https://docs.python.org/3/glossary.html#term-file-object - Technical reference for file operations and modes
π Quick Reference Card
| Try-Except Structure | try β except β else β finally |
| File Mode "r" | Read only (default) |
| File Mode "w" | Write (erases existing!) |
| File Mode "a" | Append to end |
| File Mode "r+" | Read and write |
| with statement | Auto-closes files |
| file.read() | Read entire file |
| file.readline() | Read single line |
| file.readlines() | Read all lines as list |
| file.write(s) | Write string (no auto \n) |
| raise Exception | Manually trigger error |
| Common Exceptions | ValueError, TypeError, FileNotFoundError, ZeroDivisionError |
Code Template:
try:
with open("file.txt", "r", encoding="utf-8") as f:
data = f.read()
except FileNotFoundError:
print("File not found")
except Exception as e:
print(f"Error: {e}")
finally:
print("Cleanup complete")