안녕하세요! 지난 시간에는 파이썬의 csv 모듈을 사용하여 CSV 파일을 읽고 쓰는 방법에 대해 알아보았습니다. 이제 구조화된 데이터를 파일로 저장하고 불러올 수 있게 되었죠!
이번 시간에는 프로그램이 실행되는 동안 발생할 수 있는 예상치 못한 문제, 즉 **예외(Exception)**를 안전하게 처리하는 방법에 대해 알아보겠습니다. 예외 처리는 프로그램이 오류 때문에 갑자기 멈추는 것을 방지하고, 사용자에게 친화적인 메시지를 보여주거나 문제 상황을 복구할 수 있도록 돕는 매우 중요한 기법입니다.
파이썬에서는 주로 try-except 구문을 사용하여 예외를 처리합니다. 마치 "일단 이 작업을 시도해보고, 만약 문제가 발생하면 이렇게 처리해라"라고 컴퓨터에게 지시하는 것과 같습니다.
Part 1: 예외(Exception)란 무엇인가? 왜 예외 처리가 필요할까?
프로그래밍에서 예외는 프로그램 실행 중에 발생하는 오류를 의미합니다. 예를 들어, 존재하지 않는 파일을 열려고 하거나, 숫자를 0으로 나누려 할 때 예외가 발생합니다. (1-8 포스팅에서 배웠던 런타임 오류, TypeError, ValueError 등도 모두 예외의 일종입니다.)
1. 예외가 발생했을 때의 기본 동작
예외가 발생하면, 프로그램은 기본적으로 더 이상 진행하지 못하고 강제로 **중단(Crash)**됩니다. 이때 파이썬은 Traceback과 함께 어떤 예외가 발생했는지 메시지를 터미널에 출력합니다.
예시: 예외 발생 시 프로그램 중단
# 파일 이름: exception_without_handling.py
print("프로그램 시작.")
# 0으로 나누는 예외 발생
try:
result = 10 / 0
print(f"나눗셈 결과: {result}")
except ZeroDivisionError:
print("0으로 나눌 수 없습니다.")
print("프로그램 끝.")
[VS Code 터미널 출력]

2. 왜 예외 처리가 필요할까요?
- 프로그램 안정성: 예외가 발생해도 프로그램이 강제로 종료되지 않고 계속 실행되도록 합니다.
- 사용자 경험 개선: 오류 메시지 대신 친절한 안내 메시지를 제공하여 사용자가 혼란스러워하지 않도록 돕습니다.
- 문제 복구: 예외 발생 시 특정 작업을 수행(예: 파일 닫기, 데이터 롤백, 기본값 설정)하여 문제 상황을 복구할 수 있습니다.
- 디버깅 용이성: 어떤 종류의 예외가 어디서 발생했는지 정확히 파악하고 기록할 수 있습니다.
Part 2: try-except 구문 - 예외 처리의 기본
예외 처리는 try 블록과 except 블록을 사용하여 구현합니다.
1. 기본 형식
try:
# 예외가 발생할 가능성이 있는 코드 (정상적으로 실행될 것으로 기대되는 코드)
except [예외_타입_이름] as [별칭]:
# 예외가 발생했을 때 실행할 코드
# (예: 오류 메시지 출력, 문제 해결 로직, 로그 기록 등)
- try 블록: 예외가 발생할 것으로 예상되는 코드를 이 블록 안에 작성합니다.
- except 블록: try 블록 안에서 특정 예외가 발생했을 때 실행되는 코드입니다.
- [예외_타입_이름]: 처리하고자 하는 예외의 종류를 명시합니다. (예: ZeroDivisionError, ValueError, FileNotFoundError 등)
- as [별칭]: (선택 사항) 발생한 예외 객체를 별칭 변수에 저장하여, except 블록 내부에서 예외에 대한 자세한 정보(예: str(e))를 얻을 수 있습니다.
예시: 0으로 나누는 예외 처리
# 파일 이름: try_except_basic.py
print("프로그램 시작.")
try:
# 이 안의 코드가 실행됩니다.
num1 = 10
num2 = 0
result = num1 / num2 # 0으로 나누는 예외 발생 지점
print(f"나눗셈 결과: {result}")
except ZeroDivisionError as e: # ZeroDivisionError가 발생하면 이 블록 실행
print("오류 발생: 숫자를 0으로 나눌 수 없습니다.")
print(f"발생한 예외 정보: {e}") # 예외 객체 출력
print("프로그램 끝.") # 예외가 처리되었으므로 프로그램이 중단되지 않고 여기까지 실행됩니다.
[VS Code 터미널 출력]

Part 3: 다양한 예외 처리 방법
하나의 try 블록에 여러 종류의 except 블록을 연결하여 다양한 예외를 처리할 수 있습니다.
1. 여러 except 블록 사용
- 여러 예외를 각기 다른 방식으로 처리하고 싶을 때 사용합니다. 예외는 위에서부터 순서대로 검사하며, 일치하는 첫 번째 except 블록만 실행됩니다.
예시: 숫자 입력 관련 예외 처리
# 파일 이름: multiple_excepts.py
def divide_numbers():
try:
num1_str = input("첫 번째 숫자를 입력하세요: ")
num2_str = input("두 번째 숫자를 입력하세요: ")
num1 = int(num1_str) # ValueError 발생 가능
num2 = int(num2_str) # ValueError 발생 가능
result = num1 / num2 # ZeroDivisionError 발생 가능
print(f"나눗셈 결과: {result}")
except ValueError: # 숫자로 변환할 수 없을 때
print("오류: 올바른 숫자를 입력해주세요.")
except ZeroDivisionError: # 0으로 나누려 할 때
print("오류: 두 번째 숫자는 0이 될 수 없습니다.")
except Exception as e: # 예상치 못한 모든 다른 예외 처리 (가장 마지막에 와야 함)
print(f"예상치 못한 오류가 발생했습니다: {e}")
print("--- 나눗셈 프로그램 시작 ---")
divide_numbers() # 정상 입력
print("--- 첫 번째 실행 완료 ---\n")
divide_numbers() # 문자열 입력 (ValueError)
print("--- 두 번째 실행 완료 ---\n")
divide_numbers() # 두 번째 숫자 0 입력 (ZeroDivisionError)
print("--- 세 번째 실행 완료 ---")
[VS Code 터미널 출력 (사용자 입력 포함)]

(괄호 [] 안의 내용은 사용자가 직접 입력하는 부분입니다.)
2. except만 사용 (모든 예외 처리)
- 특정 예외 타입을 명시하지 않고 except:만 사용하면, try 블록에서 발생하는 모든 종류의 예외를 처리합니다.
- 하지만 어떤 예외인지 정확히 알기 어렵기 때문에, 보통은 특정 예외를 먼저 처리하고 마지막에 except Exception as e:와 같이 사용하는 것이 좋습니다.
예시:
# 파일 이름: generic_except.py
def risky_operation():
try:
data = [1, 2]
print(data[3]) # IndexError 발생
# x = 1 / 0 # ZeroDivisionError 발생
except: # 모든 예외를 잡음
print("알 수 없는 오류가 발생했습니다.")
print("--- 일반 except 사용 예시 ---")
risky_operation()
print("--- 실행 완료 ---")
[VS Code 터미널 출력]

Part 4: else 블록과 finally 블록 (추가)
try-except 구문에는 else와 finally 블록을 추가하여 더 정교한 예외 처리를 할 수 있습니다.
1. else 블록 - 예외가 발생하지 않았을 때
- else 블록은 try 블록에서 어떤 예외도 발생하지 않았을 때만 실행됩니다.
예시:
# 파일 이름: try_except_else.py
def process_file_safety(filename):
try:
with open(filename, 'r', encoding='utf-8') as file:
content = file.read()
except FileNotFoundError:
print(f"오류: '{filename}' 파일을 찾을 수 없습니다.")
except Exception as e:
print(f"파일 처리 중 예상치 못한 오류 발생: {e}")
else: # try 블록에서 예외가 발생하지 않았을 때만 실행
print(f"'{filename}' 파일이 성공적으로 처리되었습니다.")
print("파일 내용:")
print(content[:50], "...") # 앞 50자만 출력
print("--- else 블록 예시 (성공) ---")
process_file_safety("example.txt") # 존재하는 파일 (Part 1에서 생성한 파일 사용)
print("\n--- else 블록 예시 (실패) ---")
process_file_safety("non_existent_file.txt") # 존재하지 않는 파일
[VS Code 터미널 출력]

2. finally 블록 - 예외 발생 여부와 관계없이 항상 실행
- finally 블록은 try 블록에서 예외가 발생하든 안 하든, 또는 return 문이 있든 없든 항상 마지막에 실행됩니다.
- 주로 파일 닫기, 네트워크 연결 해제, 자원 반납 등 반드시 수행되어야 하는 정리 작업에 사용됩니다. (with 구문이 대부분의 파일 작업에서 finally를 대체합니다.)
예시:
# 파일 이름: try_finally.py
def divide_safely(a, b):
try:
print("나눗셈 시작...")
result = a / b
print(f"결과: {result}")
except ZeroDivisionError:
print("0으로 나눌 수 없습니다.")
finally: # 예외 발생 여부와 상관없이 항상 실행됨
print("나눗셈 작업 종료.")
print("--- 정상 실행 경우 ---")
divide_safely(10, 2)
print("\n--- 오류 발생 경우 ---")
divide_safely(10, 0)
[VS Code 터미널 출력]

마무리하며
이번 시간에는 파이썬에서 프로그램 실행 중 발생하는 예외(오류)를 안전하게 처리하는 try-except 구문에 대해 자세히 알아보았습니다.
- try: 예외 발생 가능성이 있는 코드를 작성합니다.
- except: 특정 예외가 발생했을 때 실행될 코드를 작성합니다.
- else: try 블록에서 예외가 발생하지 않았을 때만 실행됩니다.
- finally: 예외 발생 여부와 상관없이 항상 실행됩니다.
예외 처리는 프로그램의 안정성과 사용자 경험을 향상시키는 데 매우 중요합니다. 이제 여러분은 예상치 못한 문제에도 멈추지 않고, 유연하게 대처하는 프로그램을 만들 수 있습니다!
다음 포스팅에서는 개발자가 직접 예외를 발생시키거나(raise), 자신만의 예외를 정의하여 사용하는 방법을 알아보겠습니다.
궁금한 점이 있다면 언제든지 질문해주세요! 다음 포스팅에서 만나요!
'Python' 카테고리의 다른 글
6-2. 생성자(__init__)와 인스턴스 변수 (0) | 2025.06.29 |
---|---|
5-5. raise와 사용자 정의 예외 (0) | 2025.06.29 |
5-3. CSV 파일 다루기 (0) | 2025.06.27 |
5-2. 파일 쓰기(write, with 구문) (0) | 2025.06.27 |
4-6. 재귀 함수 이해하기 (0) | 2025.06.27 |