Python 강좌 / 예외 처리하기: try·except·else·finally·raise

예외 처리는 정상 작업 중 예상 가능한 실패를 구분해 복구하거나 호출자에게 전달하는 방법입니다. try 범위를 작게 잡고 처리할 수 있는 예외만 잡아야 실제 오류를 숨기지 않습니다.

try·except·else·finally의 역할

try의 작업에서 예외가 생기면 일치하는 except로 이동합니다. else는 예외 없이 try가 끝났을 때 실행하고 finally는 정상 종료나 예외 여부와 관계없이 정리 작업에 사용합니다. finally에서 return을 하면 진행 중인 예외나 반환값을 가릴 수 있으므로 피합니다.

관련 동작과 지원 조건은 Python: errors에서 확인할 수 있습니다.

프로그램의 규칙 위반을 명시할 때는 raise로 예외를 발생시킵니다. 입력을 받는 화면에서 복구할 수 있는 오류와 저장소 장애처럼 상위 계층에 알려야 하는 오류를 구분합니다.

실패 기록과 정리 보장은 오류 메시지 읽고 디버거·logging으로 문제 찾기 및 데코레이터와 컨텍스트 매니저 이해하기에서 사용하는 규칙과 연결됩니다.

전체 예제와 실행 결과

별도의 실습 폴더에서 아래 파일을 UTF-8로 저장합니다. 가상환경을 선택한 터미널에서 python exceptions_demo.py 명령으로 실행합니다. macOS·Ubuntu에서 가상환경을 사용하지 않는 경우 명령 이름을 python3으로 바꿉니다.

exceptions_demo.py 파일의 전체 내용입니다.

def parse_amount(text):
    amount = int(text)
    if amount < 0:
        raise ValueError("amount must be nonnegative")
    return amount

for text in ["8000", "abc", "-1"]:
    try:
        amount = parse_amount(text)
    except ValueError as error:
        print("invalid:", text)
    else:
        print("accepted:", amount)
    finally:
        print("checked")

예상 결과는 다음과 같습니다.

accepted: 8000
checked
invalid: abc
checked
invalid: -1
checked

잡아야 하는 오류와 전달할 오류

int 변환은 ValueError, 파일 읽기는 FileNotFoundError·PermissionError 등이 발생할 수 있습니다. 모든 예외를 except Exception: pass로 없애면 실패한 상태에서 다음 작업이 계속됩니다. 알 수 없는 오류는 문맥을 남기고 다시 raise하여 실패를 드러내는 편이 낫습니다.

파일·데이터베이스 연결 정리는 가능하면 with 같은 컨텍스트 관리 기능에 맡깁니다. finally로 직접 정리할 때도 자원이 실제 생성되었는지 확인해야 합니다. 예외를 새 오류로 바꾸려면 raise NewError(...) from error로 원인을 연결할 수 있습니다.

예외를 잡고 return하면 호출자는 반환값을 받고 정상 경로를 계속합니다. 반대로 except 안의 단독 raise는 원래 예외를 호출자에게 다시 전달합니다. 기록만 하고 계속하는 코드가 의도한 복구인지, 실패를 숨기는지 구분해야 합니다. finally는 정리를 위한 곳이며 여기서 return하면 기존 예외나 반환값을 가릴 수 있으므로 주의합니다.

정상·실패 경로를 모두 실습하기

  1. 0은 정상 입력으로 허용되는지 확인합니다.
  2. 빈 문자열은 int 변환 단계에서 실패하는지 확인합니다.
  3. 문자 입력과 음수 모두 invalid이지만 내부 원인은 다른지 예외 메시지를 잠시 출력해 비교합니다.

예외 메시지에 비밀번호·토큰·개인정보가 포함될 수 있으므로 그대로 로그나 사용자 화면에 노출하지 않습니다. 사용자에게는 수정 가능한 안내를 주고 검증 기록에는 필요한 범위의 원인을 남깁니다.