개요
프로그래밍을 하다 보면 예상치 못한 문제에 부딪히기 마련입니다. 사용자가 잘못된 값을 입력하거나, 존재하지 않는 파일을 열려고 하는 등 다양한 상황에서 에러 또는 예외(Exception)가 발생할 수 있습니다. 이러한 예외를 제대로 처리하지 않으면 프로그램이 갑자기 멈춰버려 사용자 경험을 크게 해치게 됩니다.
이번 글에서는 파이썬을 예시로 들어, 예외가 무엇인지 알아보고 프로그램의 안정성을 높이는 예외 처리 방법에 대해 자세히 살펴보겠습니다.
예외(Exception)란 무엇인가?
프로그래밍에서 예외란 프로그래밍이 실행되는 도중 발생하는 예상치 못한 문제를 말합니다. 보통 에러와 혼용해서 쓰이기도 하지만, 엄밀히 말하면 에러는 시스템 자체의 문제(메모리 부족, 하드웨어 오류 등)를 의미하고, 예외는 개발자가 미리 예측하고 처리할 수 있는 문제들을 지칭합니다.
예외는 마치 운전 중에 갑자기 나타난 장애물과 같습니다. 장애물(예외)을 피하지 못하면 사고(프로그램 중단)가 발생합니다. 하지만 운전자가 핸들을 꺾어(예외 처리) 장애물을 피하면 안전하게 계속 주행할 수 있습니다. 예외 처리는 이렇게 예상치 못한 문제를 우아하게 해결하고, 프로그램이 중단되지 않고 안정적으로 동작하도록 만드는 중요한 기술입니다.
주요 예외 종류
파이썬에는 다양한 종류의 예외가 존재합니다.
- NameError : 정의되지 않는 변수나 함수를 호출했을 때 발생합니다.
- IndexError : 리스트, 튜플 등의 시퀀스 타입에서 존재하지 않는 인덱스에 접근하려 할 때 발생합니다.
- ValueError : 함수에 유효하지 않은 인자를 전달했을 때 발생합니다. 예를 들어 int() 함수에 숫자로 변환할 수 없는 문자열('abc')을 넘길 때 발생합니다.
- FileNotFoundError : 존재하지 않는 파일을 열려고 시도했을 때 발생합니다.
- ZeroDivisionError : 숫자를 0으로 나눌 때 발생합니다.
try-except로 예외 처리하기
파이썬에서 예외 처리를 위한 가장 기본적인 방법은 바로 try-except 구문입니다. 이 구문은 다음과 같이 작동합니다.
- try 블록 : 예외가 발생할 가능성이 있는 코드를 작성합니다.
- except 블록 : try 블록에서 예외가 발생했을 때 실행할 코드를 작성합니다.
기본적인 사용법
아래 코드에서 try 블록의 10 / 0은 ZeroDivisionError를 일으킵니다. 그러면 파이썬은 즉시 except zeroDeivisionError 블록으로 이동하여 0으로 나눌 수 없습니다를 출력하고 프로그램은 중단되지 않고 계속 실행됩니다.
try:
# 예외가 발생할 수 있는 코드
num = 10 / 0
except ZeroDivisionError:
# 예외가 발생하면 실행되는 코드
print("0으로 나눌 수 없습니다!")
여러 예외 처리하기
한 try 블럭에서 여러 종류의 예외가 발생할 수 있다면, except를 여러 개 사용하거나 하나의 except에 튜플 형태로 묶어 처리할 수 있습니다.
try:
index = int(input("인덱스 번호를 입력하세요: "))
my_list = [1, 2, 3]
print(my_list[index])
except ValueError:
print("숫자만 입력해 주세요!")
except IndexError:
print("존재하지 않는 인덱스입니다.")
예외 객체 얻기(as 키워드)
except 문에 as 키워드를 사용하면 발생한 예외 객체를 변수에 담아 더 자세한 정보를 확인할 수 있습니다.
try:
file = open("non_existent_file.txt", 'r')
except FileNotFoundError as e:
print(f"파일을 찾을 수 없습니다. 에러 메시지: {e}")
보조적인 예외 처리 구문들
try-else
try 블록에서 예외가 발생하지 않았을 때 실행할 코드가 있다면 else 블록을 사용할 수 있습니다. else 블록은 try와 except 사이에 위치해야 합니다.
try:
num = int(input("숫자를 입력하세요: "))
except ValueError:
print("유효한 숫자를 입력하지 않았습니다.")
else:
print(f"입력한 숫자는 {num} 입니다. 예외가 발생하지 않았네요!")
try-finally
try 블록의 예외 발생 여부와 관계없이 항상 실행해야 하는 코드가 있다면 finally 블록에 작성합니다. 이는 주로 파일을 닫거나 네트워크 연결을 끊는 등 반드시 마무리해야 하는 작업에 유용합니다.
try:
# 파일 열기
file = open("test.txt", "w")
file.write("Hello, World!")
# 예외 발생 (강제)
# raise ValueError
finally:
# 예외 발생 여부와 상관없이 파일 닫기
file.close()
print("파일 닫기 완료!")
고급 예외 처리 활용
오류 회피하기(Bad Practice)
간혹 모든 예외를 무시하고 넘어가기 위해 except 블록에 아무것도 작성하지 않거나 pass를 사용하는 경우가 있습니다.
이러한 방법은 디버깅을 매우 어렵게 만들고, 예상치 못한 문제를 야기할 수 있으므로 절대 사용하지 않는 것이 좋습니다.
try:
# 어떤 위험한 코드
...
except Exception:
pass # 모든 예외를 무시
오류 일부러 발생시키기(raise)
때로는 개발자가 특정 조건에서 의도적으로 예외를 발생시켜야 할 때가 있습니다. 이때 raise 키워드를 사용합니다.
이처럼 raise는 함수가 잘못된 값을 받았을 때, 호출한 쪽에 문제가 있음을 명확하게 알려주는 데 사용됩니다.
def validate_age(age):
if age < 0:
raise ValueError("나이는 음수가 될 수 없습니다.")
print(f"나이: {age}")
try:
validate_age(-5)
except ValueError as e:
print(e) # 나이는 음수가 될 수 없습니다.
나만의 예외 만들기(사용자 정의 예외)
파이썬의 기본 예외 외에, 프로그램의 특성에 맞는 새로운 예외를 직접 만들 수도 있습니다. 보통 Exception 클래스를 상속받아 정의합니다.
class MyCustomError(Exception):
"""나만의 사용자 정의 예외입니다."""
def __init__(self, message="사용자 정의 에러가 발생했습니다."):
self.message = message
super().__init__(self.message)
def run_my_app():
if True: # 특정 조건
raise MyCustomError("이건 특별한 문제 상황이야!")
try:
run_my_app()
except MyCustomError as e:
print(e) # 이건 특별한 문제 상황이야!
결론
예외 처리는 프로그램의 안정성을 보장하고 사용자에게 더 나은 경험을 제공하는 필수적인 기술입니다. 단순한 try-except 구문부터 finally, else, 그리고 raise와 사용자 정의 예외까지, 파이썬이 제공하는 다양한 기능을 적재적소에 활용하면 예상치 못한 상황에서도 견고하게 동작하는 프로그램을 만들 수 있습니다.
안정적인 프로그램은 예외적인 상황을 현명하게 다루는 것에서 시작됩니다. 이제 여러분의 코드에 튼튼한 예외 처리 방어막을 세워보세요!
'Dev > Python' 카테고리의 다른 글
[Python] 인자 규약 (0) | 2025.09.25 |
---|---|
[Python] 함수 시그니처 (0) | 2025.09.24 |
[Python] 모듈(Module) & 패키지(Package) (0) | 2025.09.23 |
[Python] 타입 힌트 (0) | 2025.09.22 |
[Python] 파이썬 디스크립터, __get__ , __set__ 은 공개(Public) 메서드일까? (0) | 2025.09.20 |