Exception Handling
Unexpected situations always occur during program execution — files don't exist, network disconnects, users enter invalid data... Without handling these "exceptions," the program crashes. Exception handling allows your program to recover from errors and provide user-friendly prompts instead of cryptic error messages.
1. What is an Exception
An exception is an error that occurs during program execution. If an exception is not handled, the program terminates:
# This code will crash
# print(10 / 0) # ZeroDivisionError: division by zero
# int("abc") # ValueError: invalid literal for int()
# open("non_existent.txt") # FileNotFoundError
Use try-except to handle these errors gracefully:
Example: try-except Handling Division and Input Errors
try:
number = int(input("Enter a number: "))
result = 10 / number
print(f"10 / {number} = {result}")
except ValueError:
print("That's not a valid number!")
except ZeroDivisionError:
print("Cannot divide by zero!")
Sample run:
Enter a number: abc
That's not a valid number!
Tip: Exception handling philosophy: Instead of using
tryto "predict all possible errors," it's about "doing things first and dealing with problems when they arise." The Python community calls it: "It's easier to ask for forgiveness than permission" (EAFP).
2. Complete try-except Structure
Example: try-except-else-finally Full Structure
try:
# Code that might error
file = open("data.txt", "r", encoding="utf-8")
content = file.read()
number = int(content)
print(f"The number is: {number}")
except FileNotFoundError:
print("File not found!")
except ValueError:
print("File content is not a valid number!")
else:
# Executes when no exception occurs
print("Successfully read and converted!")
finally:
# Always executes, regardless of exceptions
print("Cleanup: closing file")
try:
file.close()
except NameError:
pass
| Part | When it executes | Purpose |
|---|---|---|
try |
Always | Put potentially error-prone code here |
except |
When the specified exception occurs | Handle the error |
else |
When no exception occurs | Logic after success |
finally |
Always (with or without exception) | Clean up resources (close files/release connections) |
Tip: In real development,
elseis used less frequently, whilefinallyis used extensively. Thewithstatement (context manager) handles resource release automatically and can often replacefinally.
3. Common Exception Types
# ZeroDivisionError — division by zero
# int("abc") # ValueError — invalid value
# [1, 2][5] # IndexError — index out of range
# {"a": 1}["b"] # KeyError — key doesn't exist
# open("x.txt") # FileNotFoundError — file not found
# 10 + "hello" # TypeError — type error
# import nonexistent # ModuleNotFoundError — module not found
Catching All Exceptions (Not Recommended)
Example: Correct vs Wrong Way to Catch Exceptions
try:
# Some code
pass
except: # Catches ALL exceptions
print("Something went wrong")
try:
pass
except Exception as e: # Catches known exceptions
print(f"Error: {e}")
Warning: Bare
except:is not recommended — it catches system exceptions likeKeyboardInterrupt(Ctrl+C) andSystemExit, preventing normal program termination. Useexcept Exception as einstead. Best practice is to only catch the specific exception types you expect.
4. raise: Raising Exceptions Explicitly
Sometimes you need to tell the caller "something went wrong." Use raise:
Example: raise to Raise an Exception
def divide(a, b):
if b == 0:
raise ValueError("Cannot divide by zero!")
return a / b
try:
result = divide(10, 0)
except ValueError as e:
print(f"Error: {e}") # Error: Cannot divide by zero!
Password Strength Check Example
Example: raise for Password Validation
def validate_password(password):
"""Validate password strength; raise exception if conditions aren't met"""
if len(password) < 6:
raise ValueError("Password must be at least 6 characters")
if not any(c.isdigit() for c in password):
raise ValueError("Password must contain a digit")
if not any(c.isalpha() for c in password):
raise ValueError("Password must contain a letter")
return True
try:
validate_password("123")
except ValueError as e:
print(f"Invalid password: {e}")
Tip: When to use
raise? When a function encounters a situation that "shouldn't happen" — invalid parameter values, unsatisfied preconditions, unavailable dependencies. Raise an exception to let the caller decide how to handle it, rather than silently swallowing the error inside the function.
5. Custom Exception Classes
You can create your own exception types for more precise error information:
Example: Custom Exceptions for Bank Withdrawal
class BalanceError(Exception):
"""Insufficient balance exception"""
pass
class AccountLockedError(Exception):
"""Account locked exception"""
pass
def withdraw(balance, amount):
if amount > balance:
raise BalanceError(f"Insufficient balance! Need {amount}, have {balance}")
if balance < 0:
raise AccountLockedError("Account is locked")
return balance - amount
try:
withdraw(100, 200)
except BalanceError as e:
print(f"Transaction failed: {e}")
except AccountLockedError as e:
print(f"Transaction failed: {e}")
Tip: Custom exceptions make your code clearer — callers can precisely handle different types of errors. Simply inherit from
Exception; usually just a class name is sufficient, no extra methods needed.
6. logging: Professional Error Logging
Using print() for error messages works in simple scripts, but in production projects, use the logging module:
Example: logging Configuration and Usage
import logging
# Basic configuration
logging.basicConfig(
level=logging.INFO, # Log level
format="%(asctime)s [%(levelname)s] %(message)s",
handlers=[
logging.FileHandler("app.log", encoding="utf-8"), # Write to file
logging.StreamHandler() # Also output to console
]
)
# Different log levels
logging.debug("Debug info") # Debugging, usually not output
logging.info("Application started successfully") # General info
logging.warning("Disk usage at 85%") # Warning
logging.error("Database connection failed") # Error
logging.critical("System crash!") # Fatal error
Output (written to both file and console):
2026-06-23 16:00:00,123 [INFO] Application started successfully
2026-06-23 16:00:00,124 [WARNING] Disk usage at 85%
2026-06-23 16:00:00,124 [ERROR] Database connection failed
Tip: Benefits of
loggingoverprint(): 1) Can output to both console and file simultaneously. 2) Has level control (show all during development, only WARNING+ in production). 3) Auto-includes timestamps. 4) No need to delete a bunch ofprint()statements before release.
Common Use Cases
- User input validation: Use
try-exceptto handleint()conversion errors, providing user-friendly prompts. - File operations: Use
try-exceptto handle file-not-found, permission-denied, and other errors. - Network requests: Handle timeouts, connection failures, and data parsing errors.
- Database operations: Handle connection failures, SQL syntax errors, and unique constraint violations.
- API development: Use custom exceptions to precisely distinguish different error types.
FAQ
as e mean in except Exception as e?as e assigns the caught exception object to the variable e, allowing you to inspect the exception details — print(e) shows the error description, type(e).__name__ shows the exception type name. Without as e, you can still catch the exception but can't see detailed error information.if for errors you can predict in advance (like checking for zero divisor). Use try-except for errors you can't predict (like network requests, file operations). The Python community's EAFP style leans toward using try — but this is a matter of aesthetics, and both approaches have their use cases.finally always execute?try block has return, break, or continue, finally still executes. The only exception is when the program is forcibly terminated (e.g., os._exit() or a power outage). This makes finally an excellent place for resource cleanup.Summary
- Exceptions are runtime errors; handle them with
try-except - Structure:
try->except(by specific exception type) ->else(no exception) ->finally(always executes) - Common exceptions:
ValueError,TypeError,FileNotFoundError,ZeroDivisionError,IndexError,KeyError raisethrows exceptions explicitly, letting the caller handle errors- Custom exception classes inherit from
Exception, precisely distinguishing error types - The
loggingmodule replacesprint(), supporting level control, file output, and timestamps
Exercises
-
Beginner (Difficulty: Star): Write a program that asks the user for two numbers and computes their division. Use
try-exceptto handleValueError(input is not a number) andZeroDivisionError(division by zero), each with a friendly error message. -
Intermediate (Difficulty: Star-Star): Write a function
read_int_from_file(filename)that reads the first number from a file and returns it. Use try-except to handle: file not found, file content is not a valid number, file is empty. Return a different error message for each case. -
Advanced (Difficulty: Star-Star-Star): Write a "safe calculator" program. The user enters an expression (e.g.,
10 / 3), and the program computes and outputs the result. Requirements: 1) Usetry-exceptto handle division by zero, value errors, and type errors. 2) Useloggingto record each calculation operation (INFO) and error (ERROR) to acalculator.logfile. 3) Supportexitto quit. Hint: Useeval()to evaluate the expression (note security concerns — acceptable for this exercise).



