Docs
error handling
08 - Error & Exception Handling
š What You'll Learn
- ā¢What are exceptions
- ā¢try-except blocks
- ā¢Handling specific exceptions
- ā¢else and finally clauses
- ā¢Raising exceptions
- ā¢Custom exceptions
- ā¢Best practices
ā What are Exceptions?
Exceptions are errors that occur during program execution. Without handling, they crash your program.
# This will crash!
print(10 / 0) # ZeroDivisionError
# This too!
int("hello") # ValueError
# And this!
my_list = [1, 2, 3]
print(my_list[10]) # IndexError
š”ļø try-except Block
Catch and handle exceptions gracefully.
# Basic try-except
try:
result = 10 / 0
except:
print("An error occurred!")
# Better: catch specific exception
try:
result = 10 / 0
except ZeroDivisionError:
print("Cannot divide by zero!")
šÆ Handling Specific Exceptions
try:
value = int(input("Enter a number: "))
result = 10 / value
print(f"Result: {result}")
except ValueError:
print("That's not a valid number!")
except ZeroDivisionError:
print("Cannot divide by zero!")
Multiple Exceptions in One Block
try:
# code that might fail
pass
except (ValueError, TypeError):
print("Value or Type error occurred!")
Get Exception Details
try:
result = 10 / 0
except ZeroDivisionError as e:
print(f"Error: {e}")
print(f"Error type: {type(e).__name__}")
š Common Exceptions
| Exception | Cause |
|---|---|
ZeroDivisionError | Division by zero |
ValueError | Wrong value type |
TypeError | Wrong type operation |
IndexError | Index out of range |
KeyError | Dict key not found |
FileNotFoundError | File doesn't exist |
AttributeError | Invalid attribute |
ImportError | Import failure |
NameError | Variable not defined |
PermissionError | Permission denied |
ā else Clause
The else block runs if no exception occurred.
try:
value = int("42")
except ValueError:
print("Invalid number")
else:
print(f"Success! Value is {value}")
š finally Clause
The finally block always runs, whether exception occurred or not.
try:
file = open("data.txt", "r")
data = file.read()
except FileNotFoundError:
print("File not found")
finally:
print("Cleanup code runs here")
# Close file if it was opened
Complete Structure
try:
# Code that might raise an exception
result = risky_operation()
except SomeException as e:
# Handle specific exception
print(f"Error: {e}")
except AnotherException:
# Handle another exception
print("Another error")
else:
# Runs if no exception occurred
print("Success!")
finally:
# Always runs (cleanup code)
print("Cleaning up...")
š Raising Exceptions
Use raise to throw an exception.
def validate_age(age):
if age < 0:
raise ValueError("Age cannot be negative")
if age > 150:
raise ValueError("Age seems unrealistic")
return True
try:
validate_age(-5)
except ValueError as e:
print(f"Validation error: {e}")
Re-raising Exceptions
try:
risky_operation()
except Exception as e:
print(f"Logging error: {e}")
raise # Re-raise the same exception
šØ Custom Exceptions
Create your own exception classes.
# Define custom exception
class InsufficientFundsError(Exception):
"""Raised when account has insufficient funds."""
def __init__(self, balance, amount):
self.balance = balance
self.amount = amount
self.message = f"Cannot withdraw ${amount}. Balance is ${balance}"
super().__init__(self.message)
# Use custom exception
class BankAccount:
def __init__(self, balance):
self.balance = balance
def withdraw(self, amount):
if amount > self.balance:
raise InsufficientFundsError(self.balance, amount)
self.balance -= amount
return amount
# Handle custom exception
try:
account = BankAccount(100)
account.withdraw(150)
except InsufficientFundsError as e:
print(f"Error: {e}")
print(f"Tried to withdraw: ${e.amount}")
print(f"Available balance: ${e.balance}")
š³ Exception Hierarchy
BaseException
āāā SystemExit
āāā KeyboardInterrupt
āāā GeneratorExit
āāā Exception
āāā StopIteration
āāā ArithmeticError
ā āāā ZeroDivisionError
ā āāā OverflowError
āāā LookupError
ā āāā IndexError
ā āāā KeyError
āāā OSError
ā āāā FileNotFoundError
ā āāā PermissionError
āāā ValueError
āāā TypeError
āāā ... (many more)
# Catch all exceptions (use carefully!)
try:
risky_code()
except Exception as e: # Catches most exceptions
print(f"Error: {e}")
# Don't do this (catches SystemExit, KeyboardInterrupt too!)
# except BaseException:
š§ Best Practices
1. Be Specific
# ā Bad - too broad
try:
do_something()
except:
pass
# ā
Good - specific exception
try:
do_something()
except ValueError as e:
handle_value_error(e)
2. Don't Silence Exceptions
# ā Bad - hides bugs
try:
process_data()
except Exception:
pass
# ā
Good - at least log it
try:
process_data()
except Exception as e:
logging.error(f"Error processing data: {e}")
3. Use Context Managers
# ā Okay but verbose
try:
f = open('file.txt')
data = f.read()
finally:
f.close()
# ā
Better - context manager
with open('file.txt') as f:
data = f.read()
4. EAFP vs LBYL
# LBYL (Look Before You Leap)
if 'key' in dictionary:
value = dictionary['key']
# EAFP (Easier to Ask Forgiveness than Permission) - Pythonic!
try:
value = dictionary['key']
except KeyError:
value = default_value
# Even better for dicts:
value = dictionary.get('key', default_value)
š” assert Statement
Assert conditions that should always be true.
def calculate_average(numbers):
assert len(numbers) > 0, "List cannot be empty"
return sum(numbers) / len(numbers)
# Assertions can be disabled with -O flag
# Don't use for input validation in production!
š Chained Exceptions
Show the cause of an exception.
try:
value = int("abc")
except ValueError as e:
raise RuntimeError("Failed to parse value") from e
šÆ Next Steps
After mastering exceptions, proceed to 09_oop to learn Object-Oriented Programming!