예외(Exception) 란 코드를 실행하는 중에 발생하는 에러를 뜻합니다. 예외가 발생하면 프로그램이 그 자리에서 멈춰버리기 때문에, 예외 처리를 통해 프로그램이 중단되지 않고 계속 실행될 수 있도록 대응해줘야 합니다.
# 예외 처리 없이 실행하면 프로그램이 중단됨
print(10 / 0) # ZeroDivisionError: division by zero
try 블록에 실행할 코드를 넣고, except 블록에 예외가 발생했을 때 처리할 코드를 넣습니다.
# 기본 예외 처리
try:
result = 10 / 0
except:
print("예외가 발생했습니다.") # 예외가 발생했습니다.
except 뒤에 예외 이름을 지정하면 특정 예외만 처리할 수 있습니다. 여러 예외를 각각 처리하는 것도 가능합니다.
# 특정 예외만 처리
try:
x = int(input("숫자를 입력하세요: "))
result = 10 / x
except ValueError:
print("숫자가 아닌 값을 입력했습니다.")
except ZeroDivisionError:
print("0으로 나눌 수 없습니다.")
as 키워드로 변수를 지정하면 발생한 예외의 에러 메시지를 받아올 수 있습니다.
# 에러 메시지 받아오기
try:
result = 10 / 0
except ZeroDivisionError as e:
print(f"에러 발생: {e}") # 에러 발생: division by zero
try/except에는 else와 finally를 추가할 수 있습니다.
else 는 예외가 발생하지 않았을 때 실행되는 블록입니다. 반드시 except 다음에 위치해야 하며, except를 생략할 수 없습니다.
finally 는 예외 발생 여부와 상관없이 항상 실행되는 블록입니다. 파일 닫기, 네트워크 연결 해제처럼 반드시 수행해야 하는 정리 작업에 사용합니다. except와 else는 생략할 수 있습니다.
try:
x = int(input("숫자를 입력하세요: "))
result = 10 / x
except ZeroDivisionError as e:
print(f"에러 발생: {e}")
else:
print(f"결과: {result}") # 예외가 없을 때만 실행
finally:
print("항상 실행됩니다.") # 예외 여부와 상관없이 항상 실행
세 블록의 실행 조건을 정리하면 다음과 같습니다.
| 블록 | 실행 조건 | except 생략 가능 여부 |
|---|---|---|
except | 예외 발생 시 | — |
else | 예외 없을 시 | ❌ 불가 |
finally | 항상 실행 | ✅ 가능 |
raise 키워드로 의도적으로 예외를 발생시킬 수 있습니다. raise 아래의 코드는 실행되지 않고 바로 except 블록으로 넘어갑니다.
# raise로 예외 발생시키기
def check_age(age):
if age < 0:
raise ValueError("나이는 0보다 작을 수 없습니다.")
return age
try:
check_age(-1)
except ValueError as e:
print(f"에러 발생: {e}") # 에러 발생: 나이는 0보다 작을 수 없습니다.
예외가 발생했을 때 현재 코드 블록에 처리할 except가 없다면, except를 만날 때까지 상위 코드 블록으로 계속 올라갑니다. 최상위까지 올라가도 처리되지 않으면 프로그램이 종료됩니다.
def level3():
raise ValueError("에러 발생!") # except 없음 → 상위로 전파
def level2():
level3() # except 없음 → 상위로 전파
def level1():
try:
level2()
except ValueError as e:
print(f"level1에서 처리: {e}") # level1에서 처리: 에러 발생!
level1()
내장 예외 외에도 Exception을 상속받아 직접 예외 클래스를 만들 수 있습니다. 도메인에 맞는 명확한 예외를 정의할 수 있어 코드 가독성이 높아집니다.
# Exception을 상속받아 사용자 정의 예외 클래스 작성
class InsufficientBalanceError(Exception):
def __init__(self, balance, amount):
self.balance = balance
self.amount = amount
super().__init__(f"잔액 부족: 현재 잔액 {balance}원, 출금 요청 {amount}원")
# 사용자 정의 예외 사용
def withdraw(balance, amount):
if amount > balance:
raise InsufficientBalanceError(balance, amount)
return balance - amount
try:
withdraw(1000, 5000)
except InsufficientBalanceError as e:
print(e) # 잔액 부족: 현재 잔액 1000원, 출금 요청 5000원