파이썬에서는 예외 처리가 try/except/else/finally 구문과 raise 연산자를 통해 구현됩니다.
try는 보호되는 코드 블록을 정의합니다. 그 안에서 예외가 발생하면, 제어는 가장 가까운 적절한 except 블록으로 전달됩니다. 예외가 없으면 else 블록이 실행됩니다. finally 블록은 예외 여부와 관계없이 항상 실행됩니다 (예: 리소스 해제용).
raise 연산자는 명시적으로 예외를 발생시키거나 현재의 예외를 다시 발생시킵니다 (except 블록에서 타입을 지정하지 않는 경우).
예시:
try: x = 1 / 0 except ZeroDivisionError as e: print(f"오류: {e}") else: print("오류가 없었습니다") finally: print("항상 실행됩니다")
출력:
오류: division by zero
항상 실행됩니다
세부 사항:
질문: "try 블록과 finally 블록에서 각각 다른 예외를 raise 하면 어떻게 될까요?"
답변: finally에서의 예외가 try에서의 예외를 "가린다": 외부로 나오는 것은 finally에서 발생한 것입니다.
def foo(): try: raise ValueError("try에서") finally: raise IndexError("finally에서") try: foo() except Exception as e: print(repr(e)) # 출력: IndexError('finally에서')
이야기
ETL 프로세스에서 finally 블록에서 조건 없이 데이터베이스 연결을 닫았지만, finally에서 예외가 발생할 수 있다는 것을 잊어버렸습니다 (예: 이미 연결이 닫혀 있을 경우). 결과적으로 finally에서의 "숨겨진" 예외가 기본 코드에서의 예외를 완전히 흡수하여 디버깅을 복잡하게 만들었습니다.
이야기
여러 개의 except 체인을 사용했지만, 일반적인 except Exception 위에 구체적인 것을 두었습니다. 결과적으로 모든 특정 except가 "죽은" 상태로 남아, 저수준 예외가 별도로 캡처되지 않았으므로 특정 오류 처리가 어려웠습니다.
이야기
웹 서비스에서 except 블록에서 예외를 "raise"로 이어주지 않고 오류를 로깅했지만 실행이 계속되게 했습니다. 그 결과 실제 오류가 "사라지고", 프로그램은 잘못된 상태로 계속 실행되었습니다.