예외처리와 디버깅깅

예외 처리

예외(Exception)는 프로그램 실행 중 발생하는 오류로, 이를 적절히 처리하지 않으면 프로그램이 강제 종료될 수 있다. Python에서는 try-except 문을 사용하여 예외를 처리(Exception Handling)하고, 프로그램이 중단되지 않도록 만들 수 있다.

기능 설명
try 예외가 발생할 가능성이 있는 코드 실행
except 예외_타입 특정 예외가 발생했을 때 실행
except Exception as e 모든 예외를 처리하고 오류 메시지 출력
else 예외가 발생하지 않았을 때 실행
finally 예외 발생 여부와 관계없이 항상 실행
raise 예외_타입("메시지") 직접 예외 발생

예외 처리를 활용하면 프로그램이 예상치 못한 오류에도 안전하게 실행될 수 있다.

예외 처리 기본 구조

try:
    # 예외가 발생할 가능성이 있는 코드
except 예외_타입:
    # 예외가 발생했을 때 실행할 코드
  • try: 예외가 발생할 가능성이 있는 코드를 작성
  • except: 예외가 발생하면 실행할 코드 작성

기본 예제

1. 0으로 나누기 예외 (ZeroDivisionError)

try:
    # num = int(input("숫자를 입력하세요: "))
    num = 0
    result = 10 / num  # 0 입력 시 예외 발생
    print("결과:", result)
except ZeroDivisionError:
    print("0으로 나눌 수 없습니다.")
0으로 나눌 수 없습니다.

2. 입력값이 숫자가 아닐 때 예외 (ValueError)

try:
    # num = int(input("숫자를 입력하세요: "))  # 문자를 입력하면 예외 발생
    num = int('abc')
    print("입력한 숫자:", num)
except ValueError:
    print("올바른 숫자를 입력하세요.")
올바른 숫자를 입력하세요.

3. 여러 개의 예외 처리

try:
    # num = int(input("숫자를 입력하세요: "))
    num = 0 # num = 'abc'
    result = 10 / num
except ZeroDivisionError:
    print("0으로 나눌 수 없습니다.")
except ValueError:
    print("올바른 숫자를 입력하세요.")
except Exception as e:
    print("예외 발생:", e)
0으로 나눌 수 없습니다.

4. elsefinally 사용

try:
    # num = int(input("숫자를 입력하세요: "))
    num = 0
    result = 10 / num
except ZeroDivisionError:
    print("0으로 나눌 수 없습니다.")
except ValueError:
    print("올바른 숫자를 입력하세요.")
else:
    print("연산 결과:", result)
finally:
    print("프로그램 종료")
0으로 나눌 수 없습니다.
프로그램 종료
  • else: 예외가 발생하지 않으면 실행
  • finally: 예외 발생 여부와 관계없이 항상 실행

5. 사용자 정의 예외 (raise)

class NegativeNumberError(Exception):
    pass


try:
    # num = int(input("양수를 입력하세요: "))
    num = -1
    if num < 0:
        raise NegativeNumberError("음수는 입력할 수 없습니다.")
    print("입력한 숫자:", num)
except NegativeNumberError as e:
    print(e)
except ValueError:
    print("올바른 숫자를 입력하세요.")
음수는 입력할 수 없습니다.

6. 파일 읽기 예외 (FileNotFoundError)

try:
    with open("nonexistent.txt", "r") as file:
        content = file.read()
        print(content)
except FileNotFoundError:
    print("파일을 찾을 수 없습니다.")
파일을 찾을 수 없습니다.

디버깅

디버깅(Debugging)은 코드에서 발생하는 오류(Bug)를 찾고 수정하는 과정이다. 파이썬에서는 다양한 디버깅 도구와 기법을 통해 효율적으로 오류를 해결할 수 있다.

기본적인 디버깅 방법

assert 문 사용

특정 조건이 참(True)인지 확인하고, 그렇지 않으면 오류를 발생시켜 디버깅에 도움을 준다.

def divide(a, b):
    assert b != 0, "0으로 나눌 수 없습니다!"  # 조건이 False일 경우 AssertionError 발생
    return a / b

print(divide(10, 0))  # 오류 발생
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
Cell In[8], line 5
      2     assert b != 0, "0으로 나눌 수 없습니다!"  # 조건이 False일 경우 AssertionError 발생
      3     return a / b
----> 5 print(divide(10, 0))  # 오류 발생

Cell In[8], line 2, in divide(a, b)
      1 def divide(a, b):
----> 2     assert b != 0, "0으로 나눌 수 없습니다!"  # 조건이 False일 경우 AssertionError 발생
      3     return a / b

AssertionError: 0으로 나눌 수 없습니다!
  • 장점: 코드 내에서 조건 검증이 가능
  • 단점: 조건이 복잡할 경우 한계가 있음

내장 디버거 pdb 사용

pdb는 파이썬 내장 디버거로, 코드 실행을 중단하고 단계별로 코드 흐름을 추적할 수 있다.

디버거 삽입하기

import pdb

def buggy_function():
   a = 5
   b = 0
   pdb.set_trace()  # 디버깅 시작 지점
   c = a / b        # 오류 발생 지점
   print(c)

buggy_function()

주요 명령어

pdb 주요 명령어
명령어 설명
n 다음 줄로 이동 (Next)
s 함수 내부로 들어가기 (Step into)
c 중단점까지 계속 실행 (Continue)
q 디버거 종료 (Quit)
p 변수 값 출력 (Print)
l 코드 주변 줄 표시 (List)

IDE 디버거 사용 (예: VS Code, PyCharm)

VS CodePyCharm 같은 통합 개발 환경(IDE)에서는 그래픽 디버거를 통해 직관적으로 코드를 디버깅할 수 있다.

  1. 중단점(Breakpoint) 설정
    • 디버깅을 원하는 코드 줄 번호 옆에 중단점을 설정
  2. 디버깅 시작
    • Run > Start Debugging 또는 F5 키를 눌러 디버깅 모드로 전환
  3. 변수 추적 및 호출 스택 확인
    • 변수 값, 함수 호출 스택, 로컬/글로벌 변수 상태를 시각적으로 확인 가능

logging 모듈 사용

print()보다 더 강력하고 유연한 로그 기록을 통해 디버깅을 수행할 수 있다. 로그 레벨을 설정하여 필요한 정보만 출력 가능하다.

import logging

# 로그 레벨 설정
logging.basicConfig(level=logging.DEBUG)

def divide(a, b):
    logging.debug(f"입력 값: a={a}, b={b}")
    if b == 0:
        logging.error("0으로 나눌 수 없습니다!")
        return None
    return a / b

result = divide(10, 0)
DEBUG:root:입력 값: a=10, b=0
ERROR:root:0으로 나눌 수 없습니다!
로그 레벨 설명
DEBUG 상세한 디버깅 정보
INFO 일반적인 정보 메시지
WARNING 경고 메시지
ERROR 오류 발생 시 메시지
CRITICAL 심각한 오류 발생 시 메시지

예외 처리 활용

예외 처리로 오류 발생 시 프로그램이 강제 종료되지 않도록 방지하고, 오류 메시지를 출력하여 문제를 분석한다.

def divide(a, b):
    try:
        return a / b
    except ZeroDivisionError as e:
        print(f"오류 발생: {e}")
        return None

result = divide(10, 0)
오류 발생: division by zero

유닛 테스트 (unittest 모듈)

자동화된 테스트를 통해 코드의 정확성을 검증하고, 변경 사항으로 인한 오류를 빠르게 발견할 수 있다.

import unittest

def add(a, b):
    return a + b

class TestMathFunctions(unittest.TestCase):
    def test_add(self):
        self.assertEqual(add(2, 3), 5)
        self.assertEqual(add(-1, 1), 0)

if __name__ == '__main__':
    unittest.main()

외부 디버깅 도구 활용

그외 외부 디버깅 도구는 아래 표를 참고한다.

디버깅 도구구
도구/라이브러리 설명
ipdb pdb의 확장판으로, IPython 환경에 최적화
pylint 코드 스타일 및 오류 검사 도구
pytest 강력한 테스트 프레임워크로 디버깅 기능 지원
trace 코드 실행 경로를 추적하여 디버깅에 활용

디버깅 시 주의사항

디버깅 시 다음과 같은 점을 주의한다.

  • 작은 단위로 코드를 테스트: 코드를 작성한 후, 작은 단위로 나눠서 문제를 확인하는 것이 효율적임
  • 코드 가독성 유지: 읽기 쉬운 코드가 디버깅을 수월하게 만듦
  • 테스트 케이스 작성: 다양한 입력 값에 대해 테스트 케이스를 작성하여 오류 가능성을 줄임
  • 반복적인 코드 리뷰: 동료나 스스로 코드를 반복적으로 검토하며 오류를 사전에 예방

이러한 방법들을 상황에 맞게 활용하면 파이썬에서 효율적으로 디버깅할 수 있다.

참고자료