Python Exception Handling | try-except, else, finally, raise, Custom Exceptions
이 글의 핵심
Hands-on guide to Python exception handling: try-except chains, else/finally, raise and re-raise, custom exceptions, and practical patterns.
Introduction
“Handling errors gracefully”
Exception handling is central to building stable, maintainable Python programs.
1. Basic exception handling
try-except
# Basic form
try:
result = 10 / 0
except ZeroDivisionError:
print("Cannot divide by zero")
result = None
# Multiple exception types
try:
number = int(input("Enter a number: "))
result = 10 / number
except ValueError:
print("Please enter a valid number")
except ZeroDivisionError:
print("Enter a non-zero number")
# Bind the exception object
try:
file = open('missing.txt', 'r')
except FileNotFoundError as e:
print(f"Error: {e}")
2. try-except-else-finally
Full structure
try:
# Code that might fail
file = open('data.txt', 'r')
content = file.read()
except FileNotFoundError:
# Runs when an exception occurs
print("File not found")
else:
# Runs only if no exception in try
print(f"Read OK: {len(content)} characters")
finally:
# Always runs (cleanup)
if 'file' in locals():
file.close()
print("Done")
3. Raising exceptions (raise)
Basic raise
def divide(a, b):
if b == 0:
raise ValueError("b cannot be zero")
return a / b
try:
result = divide(10, 0)
except ValueError as e:
print(f"Error: {e}")
Re-raising
def process_data(data):
try:
result = int(data)
except ValueError:
print("Conversion failed")
raise # propagate to caller
try:
process_data("abc")
except ValueError:
print("Handled at outer level")
4. Custom exceptions
User-defined exceptions
class InsufficientBalanceError(Exception):
"""Raised when withdrawal exceeds balance."""
def __init__(self, balance, amount):
self.balance = balance
self.amount = amount
super().__init__(f"Insufficient balance: {balance} (needed: {amount})")
class BankAccount:
def __init__(self, owner, balance):
self.owner = owner
self.balance = balance
def withdraw(self, amount):
if amount > self.balance:
raise InsufficientBalanceError(self.balance, amount)
self.balance -= amount
return self.balance
# Usage
account = BankAccount("Alice", 10000)
try:
account.withdraw(15000)
except InsufficientBalanceError as e:
print(e) # Insufficient balance: 10000 (needed: 15000)
print(f"Current balance: {e.balance}")
5. Common built-in exceptions
Frequently used types
# ValueError: wrong value
try:
int("abc")
except ValueError:
print("Conversion failed")
# TypeError: wrong types
try:
"hello" + 5
except TypeError:
print("Type mismatch")
# KeyError: missing dict key
try:
data = {'name': 'Alice'}
print(data['age'])
except KeyError:
print("Key missing")
# IndexError: index out of range
try:
arr = [1, 2, 3]
print(arr[10])
except IndexError:
print("Index out of range")
# FileNotFoundError: missing file
try:
open('missing.txt', 'r')
except FileNotFoundError:
print("File not found")
6. Practical examples
Safe JSON file reading
import json
def safe_read_json(filename):
"""Read a JSON file safely."""
try:
with open(filename, 'r', encoding='utf-8') as f:
return json.load(f)
except FileNotFoundError:
print(f"File not found: {filename}")
return {}
except json.JSONDecodeError as e:
print(f"JSON parse error: {e}")
return {}
except Exception as e:
print(f"Unexpected error: {e}")
return {}
Retry logic
import time
def retry_operation(func, max_attempts=3):
"""Retry func until success or attempts exhausted."""
for attempt in range(max_attempts):
try:
return func()
except Exception as e:
print(f"Attempt {attempt + 1} failed: {e}")
if attempt < max_attempts - 1:
time.sleep(1)
else:
raise
# Usage
def unstable_operation():
import random
if random.random() < 0.7:
raise ConnectionError("connection failed")
return "success"
try:
result = retry_operation(unstable_operation)
print(result)
except Exception as e:
print(f"Final failure: {e}")
Practical tips
Exception-handling best practices
# ✅ Catch specific exceptions
try:
value = int(user_input)
except ValueError:
print("Please enter a number")
# ❌ Bare except Exception (harder to debug)
try:
value = int(user_input)
except Exception:
print("Something went wrong")
# ✅ Use the exception message
try:
file = open('data.txt', 'r')
except FileNotFoundError as e:
print(f"File error: {e}")
# ✅ Prefer context managers over manual close in finally
try:
with open('data.txt', 'r') as file:
pass
finally:
pass # file already closed by with
Summary
Key takeaways
- try-except: handle expected failures.
- finally: always runs—use for cleanup when not using
with. - raise: signal errors; bare
raisere-raises the current exception. - Custom exceptions: subclass
Exceptionand store context onself. - Best practice: catch narrow types; avoid swallowing bugs with overly broad handlers.