예외 처리를 하지 않았을 때 프로그램이 멈추는 치명적인 상황과 이를 방지하는 방어 프로그래밍의 필요성을 완벽하게 이해해요. 복잡해 보이는 에러 트레이스백 메시지에서 문제의 원인과 발생 위치를 빠르고 정확하게 찾아내는 방법을 배워요. 파이썬 try/except/else/finally 구문의 완벽한 활용법과 raise를 이용한 능동적인 예외 발생 및 처리 패턴까지 모두 익힐 수 있어요.
목차
- 프로그램이 뻗는 순간: 예외 처리가 필요한 이유
- 에러 트레이스백 무서워하지 않고 읽는 법
- 오류 vs 예외 그리고 자주 만나는 6가지 녀석들
- 에러를 안전하게 넘기는 try / except 기본 구조
- else와 finally로 완성하는 네 절 구조
- 능동적인 에러 제어: raise와 사용자 정의 예외
- 실전 응용 패턴과 초보자가 자주 하는 실수
- 자주 묻는 질문
프로그램이 뻗는 순간: 예외 처리가 필요한 이유
반복문을 돌리며 데이터를 한창 처리하다가 에러 하나 때문에 프로그램이 완전히 뻗어버린 경험 다들 한 번쯤 해보셨나요? 정말 당황스럽죠. 밤새 돌아가야 하는 크롤링 프로그램이나 대량의 엑셀 데이터를 분석하는 코드를 실행해 두고 퇴근했는데, 다음 날 아침에 와보니 딱 중간쯤에서 에러 메시지만 남기고 멈춰있을 때의 그 허탈함은 이루 말할 수 없어요.
코드 문법이 완벽하더라도 프로그램을 실행하는 도중, 즉 런타임에 예상치 못한 값이 들어오면 프로그램은 그대로 멈춰버려요. 예를 들어 사용자가 숫자를 입력해야 하는데 문자를 입력하거나, 네트워크 연결이 잠시 끊어지거나, 파일을 열어야 하는데 해당 위치에 파일이 없는 등 변수는 너무나도 많죠. 완벽한 환경이란 건 애초에 존재하지 않으니까요.
대량의 데이터를 처리하거나 24시간 돌아가야 하는 서버를 운영할 때, 단 하나의 에러 때문에 시스템 전체가 다운된다면 정말 곤란해져요. 그래서 우리는 운전할 때 돌발 상황을 대비해 방어 운전을 하듯, 코드에도 방어 프로그래밍을 적용해야 해요. 에러가 발생하더라도 프로그램이 비정상적으로 종료되지 않고, 우아하게 문제를 넘기거나 기록을 남기고 다음 작업으로 넘어가게 만드는 거죠.
반복문에서 파이썬 예외처리를 하지 않았을 때 프로그램이 어떻게 멈추는지 코드로 직접 확인해 볼게요.
위 코드를 실행해보면 10과 5는 잘 나누다가 0을 만나는 순간 치명적인 에러가 발생해요. 결국 맨 마지막 줄의 완료 메시지는 영원히 출력되지 않죠. 이처럼 단 하나의 데이터 결함이 전체 프로세스를 망가뜨리는 것을 막는 것이 바로 예외 처리의 핵심이에요.
에러 트레이스백 무서워하지 않고 읽는 법
프로그램이 멈추면 터미널이나 콘솔 창에 빨간색으로 길고 복잡한 에러 메시지가 쏟아져 나오는 걸 보셨을 거예요. 이를 트레이스백이라고 부르는데, 메시지가 길고 전부 영어로 되어 있어서 초보자분들은 지레 겁먹고 그냥 창을 닫아버리기 일쑤예요.
하지만 절대 도망치지 마세요. 읽는 요령만 알면 파이썬 에러 해결은 아주 간단한 퍼즐 맞추기가 돼요. 파이썬은 우리가 어디서 어떻게 틀렸는지 아주 친절하게 알려주고 있는 거거든요. 에러가 발생했을 때 파이썬이 출력하는 트레이스백 메시지의 구조를 살펴볼게요.
이 복잡한 메시지에서 우리가 찾아야 할 단서는 딱 세 가지예요. 이것만 순서대로 확인하면 어떤 에러든 해결의 실마리를 찾을 수 있어요.
맨 아래를 보면 에러의 종류와 구체적인 이유가 적혀 있어요. 여기서 어떤 종류의 사고가 터졌는지 파악하는 게 우선이에요.
어떤 파일의 몇 번째 줄에서 문제가 생겼는지 알 수 있어요. 내 코드가 어디서 터졌는지 정확한 위치를 알려주죠.
문제가 발생한 코드 라인을 직접 확인하며 오타나 로직의 결함을 찾아 수정해요.
이렇게 맨 아래부터 위로 한 단계씩 거슬러 올라가면 어디를 고쳐야 할지 단번에 알 수 있어요. 앞으로 빨간 글씨를 만나면 당황하지 말고 침착하게 맨 밑줄부터 읽어보는 연습을 해보세요.
📌 Note
에러 메시지가 수십 줄에 달할 때도 있어요. 이는 함수가 다른 함수를 부르고, 또 다른 함수를 부르는 과정이 겹겹이 쌓여 있기 때문이에요. 복잡한 중간 과정은 과감히 건너뛰고 오직 맨 마지막 줄과 내 파일 이름이 적힌 곳만 찾으세요.
오류 vs 예외 그리고 자주 만나는 6가지 녀석들
코드를 짜다 보면 수많은 문제에 부딪히게 되는데, 사실 오류(Error)와 예외(Exception)는 명확히 다른 개념이에요. 이 둘을 제대로 구분하는 것이 문제 해결의 첫걸음이랍니다. 아래 표를 보면 이해하기 훨씬 쉬울 거예요.
-
오류(SyntaxError): 괄호를 닫지 않거나 문법이 틀린 코드예요. 파이썬이 실행조차 거부하므로 직접 코드를 수정해야 해요.
-
예외(Exception): 문법은 맞지만 실행 중에 발생하는 문제예요. 없는 파일을 열거나 문자를 숫자로 바꿀 때 발생하며, 코드로 대처 방법을 정할 수 있어요.
SyntaxError 같은 문법 오류는 띄어쓰기를 잘못했거나 따옴표를 빼먹는 등 규칙을 어긴 경우예요. 이건 코드가 실행되기도 전에 파이썬 번역기가 파업을 선언하는 상황이라 우리가 코드 자체를 뜯어고치는 것 말고는 답이 없어요.
반면 예외는 문법은 완벽해서 실행은 잘 되다가 특정 상황에서 쿵 하고 부딪히는 문제예요. 이건 우리가 try 구문으로 대처 방법을 미리 정해둘 수 있다는 뜻이죠. 파이썬 프로그래밍을 하면서 가장 자주 만나게 될 6가지 단골 예외 상황을 코드로 보여드릴게요.
이런 단골 에러들을 만나면 아까 배운 트레이스백 읽는 법을 활용해 원인을 파악해 보세요. 어떤 값이 들어왔길래 자료형이 안 맞는지, 리스트의 길이가 몇인데 범위를 벗어났는지 확인하는 습관을 들이면 디버깅 실력이 놀라울 정도로 성장할 거예요.
에러를 안전하게 넘기는 try / except 기본 구조
안전망 설치하기
프로그램이 중간에 멈추지 않고 끝까지 무사히 돌아가게 하려면 try / except 구조를 꼭 사용해야 해요. 작동 원리는 아주 직관적이고 쉬워요. 마치 서커스단에서 공중그네를 탈 때 바닥에 안전망을 설치하는 것과 같아요.
try 블록 안에는 에러가 날지도 모르는 아슬아슬한 코드를 넣고, except 블록 안에는 진짜로 에러가 터졌을 때 안전하게 수습할 코드를 넣는 거예요. 이때 가장 중요한 건 except 뒤에 내가 어떤 예외를 잡을지 명확하게 적어주는 거예요. 그냥 뭉뚱그려서 모든 에러를 덮어버리면, 정말 심각한 문제가 생겼을 때도 원인을 파악하기 힘들어지는 대참사가 벌어지거든요.
여러 가지 예외를 안전하고 똑똑하게 처리하는 함수를 직접 만들어 볼게요.
코드에서 볼 수 있듯이, 예상되는 여러 에러 상황을 각각 다른 구문으로 나누어 섬세하게 처리할 수 있어요. 0으로 나누는 문제와 입력값이 잘못된 문제를 따로따로 대처하는 거죠.
💡 Tip
각각의 예외를 따로 처리할 수도 있지만, 성격이 비슷한 예외라면 괄호로 묶어 튜플 형태로 한 번에 잡을 수도 있어요. as e를 사용해 파이썬이 제공하는 상세 에러 메시지를 변수에 담아두면, 사용자에게 더 정확한 원인을 안내할 수 있어서 무척 편리하답니다.
else와 finally로 완성하는 네 절 구조
각 블록의 명확한 역할 분담
try와 except만 써도 훌륭하지만, 여기에 else와 finally를 더하면 상황별로 코드를 훨씬 더 깔끔하고 체계적으로 정리할 수 있어요. 퍼즐 조각이 딱 맞아떨어지는 것처럼 완벽한 구조를 만들 수 있죠. 이 네 가지 블록이 각각 어떤 역할을 하는지 알아볼게요.
-
try: 일단 무조건 실행을 시도하는 곳이에요. 에러가 발생할 가능성이 있는 코드만 최소한으로 넣으세요.
-
except: 에러가 터졌을 때만 실행돼요. 에러를 수습하고 경고 메시지를 출력하는 역할을 해요.
-
else: 에러 없이 무사히 성공했을 때만 실행돼요. 성공했을 때만 해야 하는 다음 작업을 여기에 분리하면 코드가 깔끔해져요.
-
finally: 에러가 나든 안 나든 항상 실행되는 무적의 구역이에요. 열어둔 파일 닫기나 데이터베이스 연결 해제 같은 필수 마무리 작업에 쓰여요.
이 4가지 구조가 모두 들어간 전체 실행 흐름을 코드로 살펴볼게요. 계산기를 예로 들어보겠습니다.
finally 덕분에 어떤 상황에서도 "계산을 종료합니다"라는 메시지가 출력되는 것을 확인할 수 있어요. 함수 안에서 return을 만나 일찍 끝나버려도 파이썬이 악착같이 마지막에 꼭 실행해주기 때문에 자원 관리에 필수적이에요.
능동적인 에러 제어: raise와 사용자 정의 예외
에러를 안전하게 수습하는 것도 중요하지만, 가끔은 잘못된 값이 들어왔을 때 조용히 넘어가면 더 큰 문제가 생기기 때문에 내가 직접 에러를 빵 터뜨려야 할 때도 있어요. 조용히 넘어가면 나중에 데이터가 다 꼬여버려서 돌이킬 수 없는 강을 건너게 되거든요.
이때 raise 키워드를 사용해서 예외를 고의로 던질(throw) 수 있어요. 마치 비상 정지 버튼을 누르는 것과 같죠. 명확한 에러 메시지를 함께 적어주면 이 함수를 사용하는 다른 사람이나 미래의 내가 원인을 아주 쉽게 고칠 수 있어요.
더 나아가 파이썬의 기본 Exception 클래스를 상속받으면 내 프로젝트 비즈니스 로직에 딱 맞는 이름의 예외를 직접 만들 수도 있어요. 계좌에서 돈을 뽑을 때 잔액이 부족하면 발생하는 나만의 커스텀 예외를 만들어 볼게요.
그냥 기본 ValueError가 나는 것보다 잔액부족에러라고 명시해주면 코드를 읽는 누구나 이 상황을 명확하게 이해할 수 있어요. 복잡한 시스템을 만들수록 이런 사용자 정의 예외가 정말 큰 빛을 발한답니다.
⚠️ Warning
사용자 정의 예외를 만들 때는 반드시 Exception 클래스를 상속받아야 해요. BaseException을 상속받으면 파이썬 시스템의 가장 근본적인 예외 구조를 건드리게 되어 원치 않는 부작용이 생길 수 있으니 주의하세요.
실전 응용 패턴과 초보자가 자주 하는 실수
무한 반복 입력 패턴
지금까지 배운 내용을 바탕으로 실무에서 자주 쓰는 안전한 패턴과 절대 해서는 안 되는 치명적인 실수를 짚고 넘어갈게요. 보안 게이트에서 올바른 카드를 댈 때까지 계속 문을 안 열어주는 것처럼, 사용자에게 제대로 된 값을 입력받을 때까지 계속 질문해야 하는 상황이 많아요.
이때는 while True 무한 반복문과 try / except를 섞어 쓰는 패턴이 아주 유용해요. 사용자가 나이를 제대로 입력할 때까지 반복해서 물어보는 튼튼한 코드를 작성해 볼게요.
이 패턴을 사용하면 사용자가 어떤 이상한 텍스트를 입력하더라도 프로그램이 뻗지 않고 친절하게 다시 물어보는 코드가 완성돼요. 실무에서 데이터 검증을 할 때 매일같이 쓰는 패턴이니 꼭 기억해 두세요.
❗ 중요
초보자분들이 가장 많이 하는 실수는 except: 라고만 쓰고 뒤에 예외 타입을 안 적는 거예요. 이렇게 하면 시스템 강제 종료 신호(Ctrl+C)나 단순 스펠링 오타로 인한 버그까지 싹 다 무시하고 넘어가 버려요. 나중에 어디서 무슨 문제가 생겼는지 알 길이 없어져서 디버깅이 그야말로 지옥이 된답니다. 예외 이름은 항상 명확히 적어주세요!
자주 묻는 질문
Q. 예외 처리를 안 하면 프로그램이 무조건 멈추나요? 에러가 나도 그냥 무시하고 넘어갈 수는 없나요?
파이썬은 치명적인 예외가 발생하면 시스템을 보호하기 위해 즉시 실행을 멈추고 비정상 종료되도록 설계되어 있어요. 만약 특정 에러를 무시하고 조용히 넘어가고 싶다면 반드시 try / except 구문으로 해당 에러를 명시하고, except 블록 안에 pass를 적어 의도적으로 무시하겠다고 파이썬에게 친절하게 알려줘야 해요.
Q. 콘솔에 에러 메시지(Traceback)가 너무 길게 나와서 무서워요. 어디부터 읽어야 하나요?
에러 메시지는 문제가 발생하기까지 함수가 서로를 호출한 과정을 거꾸로 추적해서 다 보여주기 때문에 길어질 수밖에 없어요. 초보자분들은 중간의 복잡한 내용은 과감히 건너뛰고 가장 마지막 줄(에러의 종류와 원인)을 먼저 읽으세요. 그리고 바로 윗줄에서 내가 직접 작성한 파일 이름과 줄 번호를 찾아가면 가장 빠르고 정확하게 문제를 해결할 수 있어요.
Q. 코드에 모든 에러를 방지하려고 except:만 썼는데, 왜 이렇게 하면 안 좋다고 하나요?
예외 타입을 콕 짚어주지 않은 빈 except: 구문은 블랙홀과 같아요. 개발자가 예상한 에러뿐만 아니라, 스펠링 오타로 생긴 버그나 사용자가 프로그램을 끄려고 누른 시스템 강제 종료(Ctrl+C) 신호까지 전부 조용히 삼켜버려요. 나중에 어디서 무슨 문제가 생겼는지 도저히 알 길이 없어지기 때문에 최소한 except Exception as e: 형태로 쓰거나 구체적인 예외 이름을 적는 습관을 들여야 해요.
Q. finally는 왜 필요한가요? 그냥 try/except 블록 바깥에 코드를 적으면 똑같이 항상 실행되는 것 아닌가요?
try 블록 안에서 함수가 return을 만나 일찍 끝나버리거나, 우리가 미처 except로 잡아내지 못한 다른 숨겨진 에러가 터져서 프로그램이 뻗는 상황을 생각해 보세요. 블록 바깥에 적어둔 코드는 이런 상황에서는 절대 실행되지 않고 그냥 종료돼요. 하지만 finally 안에 적어둔 코드는 함수를 빠져나가든 프로그램이 터지든 파이썬이 악착같이 마지막에 꼭 실행해주기 때문에 파일을 닫거나 데이터베이스 연결을 끊는 등의 중요한 작업에 필수적이에요.