본문 바로가기
카테고리 없음

예외 처리 고급편: 사용자 정의 예외 만들기

by python note 2025. 6. 9.

파이썬 예외 처리 고급: 나만의 에러 만들기 (사용자 정의 예외)

파이썬을 배우면서 예외(오류)가 발생했을 때 프로그램을 멈추지 않고 처리하는 '예외 처리'에 대해 이미 학습했습니다. 하지만 때로는 파이썬이 기본으로 제공하는 예외들로는 우리가 원하는 상황을 정확히 표현하기 어려울 수 있습니다. 이럴 때 필요한 것이 바로 사용자 정의 예외입니다.

이번 강의에서는 파이썬에서 여러분이 직접 새로운 예외를 만들고, 이를 코딩에 활용하는 방법을 배워보겠습니다. 마치 새로운 단어를 만들어서 특정 상황을 더 잘 설명하는 것과 같습니다. 사용자 정의 예외는 코드의 가독성을 높이고, 프로그램의 오류를 더 체계적으로 관리할 수 있게 돕는 강력한 도구입니다.

사용자 정의 예외는 왜 필요할까요?

여러분은 지금까지 ValueError, TypeError 등 파이썬에 내장된 다양한 예외들을 만나봤을 것입니다. 하지만 만약 여러분이 어떤 프로그램을 만들었는데, 특정 조건(예를 들어, 비밀번호가 너무 짧거나, 은행 잔고가 부족할 때)에서만 발생하는 특별한 오류 상황을 만들고 싶다면 어떨까요? 이때 기존 예외로는 의미를 명확히 전달하기 어렵습니다. 예를 들어, 비밀번호가 짧을 때 ValueError를 발생시키면, '값이 잘못되었다'는 것은 알겠지만 정확히 '비밀번호 길이가 짧다'는 것을 알기 어렵습니다.

사용자 정의 예외는 이런 특별한 상황에 딱 맞는, 새로운 '오류 이름표'를 붙여주는 것과 같습니다. 이를 통해 프로그램의 어떤 부분에서, 왜 특정 오류가 발생했는지 더 명확하게 파악하고 처리할 수 있게 됩니다. 이는 마치 비 오는 날을 '비'라고만 하지 않고, '소나기', '장맛비', '폭우' 등 더 구체적인 이름으로 불러 상황을 정확히 설명하는 것과 비슷합니다.

사용자 정의 예외 만들기 예시 1: 간단한 나만의 오류 정의하기

사용자 정의 예외를 만드는 방법은 파이썬의 '클래스'를 이용하는 것입니다. 모든 사용자 정의 예외는 파이썬의 기본 예외 클래스인 Exception을 상속(성질을 물려받는 것)받아야 합니다. 이렇게 하면 파이썬의 예외 처리 시스템 안에서 정상적으로 동작할 수 있습니다. 가장 간단하게 나만의 예외를 만들어보겠습니다.

Python
# 나만의 예외 클래스 정의하기 class MyCustomError(Exception): # 특별히 추가할 기능이 없다면 pass를 사용합니다. pass # 이 예외를 발생시키고 처리하는 코드 try: # 특정 조건에서 MyCustomError를 발생시킵니다. raise MyCustomError("이것은 내가 만든 특별한 오류 메시지입니다!") except MyCustomError as e: print(f"나만의 오류가 발생했습니다: {e}") except Exception as e: print(f"다른 종류의 오류가 발생했습니다: {e}")

위 코드를 실행하면 다음과 같은 결과가 화면에 나타납니다.

출력 결과
나만의 오류가 발생했습니다: 이것은 내가 만든 특별한 오류 메시지입니다!

이 예제에서는 MyCustomError라는 이름의 새로운 예외를 만들었습니다. 그리고 try...except 문을 사용하여 이 예외를 발생시키고 잡아서 처리하는 것을 보여주었습니다.

사용자 정의 예외 만들기 예시 2: 오류에 정보 담아서 전달하기

때로는 오류가 발생했을 때 단순히 '오류가 났다'는 메시지 외에, 어떤 값이 문제였는지 등 더 구체적인 정보를 함께 전달하고 싶을 때가 있습니다. 사용자 정의 예외 클래스에 __init__ 메서드를 추가하여 이러한 정보를 담을 수 있습니다. __init__은 클래스가 만들어질 때 자동으로 실행되는 초기화 함수라고 생각하면 됩니다. 물려받은 Exception 클래스의 초기화도 함께 호출해주는 것이 좋습니다.

Python
# 비밀번호 길이에 대한 오류를 위한 사용자 정의 예외 class PasswordTooShortError(Exception): def __init__(self, length, min_length): self.length = length self.min_length = min_length super().__init__(f"비밀번호가 너무 짧습니다: {length}자 (최소 {min_length}자 필요)") def set_password(password): MIN_LENGTH = 8 if len(password) < MIN_LENGTH: raise PasswordTooShortError(len(password), MIN_LENGTH) print("비밀번호가 성공적으로 설정되었습니다.") try: set_password("short") except PasswordTooShortError as e: print(f"오류: {e}") print(f"입력된 길이: {e.length}자, 필요한 최소 길이: {e.min_length}자") except Exception as e: print(f"예상치 못한 오류 발생: {e}")

위 코드를 실행하면 다음과 같은 결과가 화면에 나타납니다.

출력 결과
오류: 비밀번호가 너무 짧습니다: 5자 (최소 8자 필요)
입력된 길이: 5자, 필요한 최소 길이: 8자

이 예제에서는 PasswordTooShortError라는 사용자 정의 예외를 만들었습니다. 이 예외는 비밀번호의 현재 길이(length)와 최소 길이(min_length)를 함께 저장하고 전달할 수 있습니다. 덕분에 예외를 처리하는 부분에서 더 자세한 정보를 활용하여 사용자에게 친절한 메시지를 보여줄 수 있습니다.

사용자 정의 예외 만들기 예시 3: 예외에도 '가족' 만들기 (계층 구조)

여러분의 프로그램이 복잡해지면, 여러 종류의 사용자 정의 예외를 만들어야 할 수도 있습니다. 이때 이 예외들 간에 '가족 관계'처럼 계층 구조를 만들 수 있습니다. 예를 들어, '모든 오류'라는 큰 범주 아래에 '파일 관련 오류', '네트워크 관련 오류'를 두고, 다시 '파일 관련 오류' 아래에 '파일 없음 오류', '권한 없음 오류' 등을 두는 식입니다. 이렇게 하면 여러 종류의 오류를 한 번에 처리할 수도 있고, 더 세부적인 오류만 따로 처리할 수도 있습니다.

Python
# 기본 애플리케이션 오류 클래스 class ApplicationError(Exception): pass # 입력 관련 오류 클래스 (ApplicationError를 상속) class InputError(ApplicationError): def __init__(self, message, input_value): self.input_value = input_value super().__init__(f"{message} (입력 값: '{input_value}')") # 유효하지 않은 숫자 입력 오류 (InputError를 상속) class InvalidNumberError(InputError): pass # 사용자에게 숫자 입력 요청 def get_positive_number(): user_input = input("양의 숫자를 입력하세요: ") try: number = int(user_input) if number <= 0: raise InvalidNumberError("음수 또는 0은 허용되지 않습니다.", user_input) return number except ValueError: raise InvalidNumberError("올바른 숫자가 아닙니다.", user_input) try: num = get_positive_number() print(f"입력된 양의 숫자: {num}") except InvalidNumberError as e: print(f"숫자 입력 오류: {e}") print(f"문제가 된 입력 값: '{e.input_value}'") except ApplicationError as e: print(f"애플리케이션 오류 발생: {e}") except Exception as e: print(f"알 수 없는 오류 발생: {e}")

위 코드를 실행하고 "abc"를 입력하면 다음과 같은 결과가 화면에 나타납니다.

출력 결과
양의 숫자를 입력하세요: abc
숫자 입력 오류: 올바른 숫자가 아닙니다. (입력 값: 'abc')
문제가 된 입력 값: 'abc'

만약 "0"을 입력하면 다음과 같은 결과가 나타납니다.

출력 결과
양의 숫자를 입력하세요: 0
숫자 입력 오류: 음수 또는 0은 허용되지 않습니다. (입력 값: '0')
문제가 된 입력 값: '0'

이 예제에서는 ApplicationError를 가장 상위 예외로, 그 아래에 InputError, 그리고 가장 세부적인 InvalidNumberError를 두어 예외의 계층 구조를 만들었습니다. 이렇게 하면 InvalidNumberError를 직접 처리할 수도 있고, 아니면 InputError를 통해 모든 입력 관련 오류를 한 번에 처리할 수도 있습니다. 이는 프로그램의 오류 관리를 더욱 유연하고 체계적으로 만들어 줍니다.

중요:

사용자 정의 예외는 항상 Exception 클래스 또는 그 하위 클래스(예: ValueError, TypeError 등)를 상속받아야 합니다. 이를 통해 파이썬의 표준 예외 처리 메커니즘과 호환될 수 있습니다.

주의:

너무 많은 사용자 정의 예외를 만드는 것은 오히려 코드를 복잡하게 만들 수 있습니다. 내장 예외로 충분히 표현 가능한 상황이라면 굳이 새롭게 만들 필요는 없습니다. 사용자 정의 예외는 기존 예외로 명확한 의미를 전달하기 어려울 때만 활용하는 것이 좋습니다.

핵심 : 사용자 정의 예외는 class MyError(Exception): 형태로 정의하며, 특정 오류 상황을 더 명확하게 표현하고 체계적으로 관리할 수 있게 돕습니다. __init__ 메서드를 사용해 오류에 추가 정보를 담을 수 있으며, 예외 간 계층 구조를 만들 수도 있습니다.

마무리 요약

이번 시간에는 파이썬에서 여러분이 직접 사용자 정의 예외를 만드는 방법을 학습했습니다. 단순히 오류를 처리하는 것을 넘어, 발생한 오류의 의미를 더 명확하게 정의하고, 필요한 정보를 함께 전달하며, 오류들 간에 체계적인 관계를 설정할 수 있게 되었습니다.

이는 여러분의 코드를 더욱 견고하고 이해하기 쉽게 만드는 데 큰 도움이 됩니다. 이제 여러분은 파이썬의 강력한 예외 처리 기능을 한 단계 더 깊이 활용할 수 있게 되었습니다. 다음 강의에서는 파이썬에서 파일을 읽고 쓰는 기본적인 방법에 대해 배워보겠습니다.

이 강의 내용에 대해 궁금한 점이나 여러분이 만들고 싶은 사용자 정의 예외가 있다면 댓글에 남겨주세요!

다음 강의에서는 파일 입출력을 배워보겠습니다.