Back to List

Python Exception Handling — try, except, raise

Learn everything about exception handling in Python — catching, raising, and cleaning up errors — with practical examples.

Intermediate
|
10min
|
Verified (2026-07)
exception handlingtry-exceptraisefinallyerror handling
Progress0/18 (0%)

Python Exception Handling — try, except, raise

After completing this topic, you will:

Understand how errors occur in Python, how to catch errors using try/except, how to raise errors directly using raise, and how to perform cleanup operations using finally.


Errors Kill Programs

In Python, when an error occurs, the program immediately stops.

python
numbers = [1, 2, 3]
print(numbers[10]) # IndexError: list index out of range
print("This line never runs")

All code after the line where the error occurs will not be executed. If it's a web server, the server itself will crash. If it's a data analysis script, it will process 999 out of 1000 items and then fail completely.

Exception handling is "a way to handle errors without the program crashing."


try/except — Catching Errors

python
try:
result = 10 / 0
except ZeroDivisionError:
print("Cannot divide by zero")
print("Program continues") # This line will be executed!

If an error occurs within the try block, the program jumps to the except block. The program will not stop and will continue executing.

Getting the Error Message

python
try:
value = int("hello")
except ValueError as e:
print(f"Error: {e}") # Error: invalid literal for int() with base 10: 'hello'

By using as e, you can receive the error object and find out what went wrong.

Handling Multiple Errors Separately

python
def safe_divide(a, b):
try:
result = a / b
return round(result, 2)
except ZeroDivisionError:
print("Denominator cannot be zero")
return None
except TypeError:
print("Both arguments must be numbers")
return None
safe_divide(10, 0) # Denominator cannot be zero
safe_divide("10", 2) # Both arguments must be numbers
safe_divide(10, 3) # 3.33

You can handle different error types in different ways. You can also use except Exception to catch all errors at once, but it's not recommended — it makes debugging difficult because you won't know what error occurred.


Common Error Types

ErrorCauseExample
ValueErrorInvalid valueint("abc")
TypeErrorIncorrect type"3" + 5
IndexErrorIndex out of range[1,2,3][10]
KeyErrorDictionary key does not exist{"a": 1}["b"]
FileNotFoundErrorFile does not existopen("none.txt")
ZeroDivisionErrorDivision by zero10 / 0
AttributeErrorAccessing a non-existent attribute/methodNone.upper()

These are the 7 most common errors you'll encounter in everyday programming.


else and finally

python
try:
f = open("data.txt", "r")
content = f.read()
except FileNotFoundError:
print("File not found")
else:
# Only executed if the try block succeeds
print(f"Read {len(content)} characters")
finally:
# Always executed, regardless of success or failure
print("Cleanup done")
BlockExecution Timing
tryAlways attempted
exceptWhen an error occurs
elseWhen successful without errors
finallyAlways (both success and failure)

finally is used for cleanup operations such as closing files, terminating network connections, or deleting temporary files. It's code that must always be executed, whether or not an error occurred.


raise — Raising Errors Directly

python
def withdraw(balance, amount):
if amount <= 0:
raise ValueError("Withdrawal amount must be positive")
if amount > balance:
raise ValueError(f"Insufficient funds: balance={balance}, requested={amount}")
return balance - amount
try:
new_balance = withdraw(1000, 5000)
except ValueError as e:
print(f"Transaction failed: {e}")
# Transaction failed: Insufficient funds: balance=1000, requested=5000

raise is a way to declare that "this situation is not normal." It passes the responsibility to the calling side to handle the error using try/except.

Custom Error Classes

python
class InsufficientFundsError(Exception):
def __init__(self, balance, amount):
self.balance = balance
self.amount = amount
super().__init__(
f"Cannot withdraw {amount} from balance {balance}"
)
def withdraw(balance, amount):
if amount > balance:
raise InsufficientFundsError(balance, amount)
return balance - amount
try:
withdraw(1000, 5000)
except InsufficientFundsError as e:
print(e) # Cannot withdraw 5000 from balance 1000
print(e.balance) # 1000
print(e.amount) # 5000

You can inherit from Exception to create your own custom errors. This allows you to include additional information (balance, requested amount) in the error, so that the error-handling code can respond more precisely.


Real-World Pattern — File Processing

python
def read_config(filepath):
try:
with open(filepath, "r", encoding="utf-8") as f:
lines = f.readlines()
except FileNotFoundError:
print(f"Config file not found: {filepath}")
return {}
except PermissionError:
print(f"Permission denied: {filepath}")
return {}
config = {}
for i, line in enumerate(lines, 1):
line = line.strip()
if not line or line.startswith("#"):
continue
if "=" not in line:
print(f"Warning: invalid format at line {i}: {line}")
continue
key, value = line.split("=", 1)
config[key.strip()] = value.strip()
return config
# config.txt:
# host = localhost
# port = 3000
# # this is a comment
settings = read_config("config.txt")
print(settings) # {'host': 'localhost', 'port': '3000'}

This pattern is very common in real-world scenarios:

  1. File opening failures are handled with except.
  2. Incorrect lines during parsing only receive a warning and are skipped.
  3. Empty lines and comments (#) are ignored.

The program doesn't crash just because it can't open a configuration file; instead, it operates with default values or displays a warning.


Anti-Patterns — Things Not to Do

Ignoring All Errors

python
# Bad — Swallowing the error
try:
risky_operation()
except Exception:
pass # What happened? Nobody knows
# Good — At least log it
try:
risky_operation()
except Exception as e:
print(f"Warning: {e}") # or logging.warning(...)

except: pass ignores all errors. The program won't crash, but you won't know what went wrong. It will be very difficult to debug later.

Overly Broad except

python
# Bad — Catches a typo (NameError)
try:
valeu = int(input("Enter number: ")) # typo: valeu
except Exception:
print("Invalid input") # NameError, but "Invalid input"?
# Good — Catch only the expected errors
try:
value = int(input("Enter number: "))
except ValueError:
print("Invalid input — please enter a number")

Key Takeaways

SyntaxRoleWhen to Use
tryWrap code that might raise an errorExternal input, files, network, etc.
exceptCatch specific errors and handle themNeed different handling for each error type
elseExecute only on successAdditional actions when no error occurs
finallyAlways executeCleanup operations (close files, terminate connections)
raiseRaise errors directlyInvalid input, violation of business rules

The key principle of exception handling: Catch only the errors you expect, catch them as narrowly as possible, and don't ignore them. Thinking that wrapping everything in try/except will make it safe is a misconception. Incorrect exception handling can hide errors and make debugging even more difficult than when there are no exceptions.

💬 Questions & Comments

0 comments

You can post without signing in. Guest comments cannot be edited or deleted by their author.

0/2000

Loading...