예외 처리(Exception Handling)

maro·2024년 3월 18일
  • 함수나 메소드가 처리 도중 다음 명령문을 실행할 수 없는 상황
  • 오류 중 처리가능한 것을 Exception(예외) 라고 한다. 그리고 그 예외를 처리하는 것을 Exception Handling 이라고 한다.

Exception handling

Exception이 발생되어 프로그램이 더 이상 실행될 수 없는 상황을 처리(handling)해서 정상화 시키는 작업을 말한다.
try - except 구문을 이용해 처리한다.

try:
    Exception 발생가능한 코드 블록
except [Exception클래스 이름 [as 변수]] :
    처리 코드   

try block

  • Exception 발생 가능성 있는 코드와 그 코드와 연결된 코드들을 블록으로 묶는다.
    - 연결된 코드란 Exception이 발생 안해야만 실행되는 코드를 말한다.

except block

  • 발생한 Exception을 처리하는 코드 블록을 작성한다.
    - try block의 코드를 실행하다 exception이 발생하면 except block이 실행된다. Exception이 발생하지 않으면 실행되지 않는다.
  • try block에서 발생한 모든 Exception을 처리하는 경우 except: 로 선언한다.
  • try block에서 발생한 특정 Exception만 따로 처리할 경우 except Exception클래스 이름 을 선언한다.
    - 모든 Exception들은 클래스로 정의 되어 있다. 그 클래스 이름을 적어준다.
    - Exception 들 별로 각각 처리할 수 있으면 이 경우 except 구문(처리구문)을 연속해서 작성하면 된다.
  • try block에서 발생한 특정 Exception만 따로 처리하고 그 Exception이 왜 발생했는지 등의 정보를 사용할 경우 except Exception 클래스 이름 as 변수명 으로 선언하고 변수명을 이용해 정보를 조회한다.
print("시작")             # 1. 
try:
    n = input("정수:")  # 2  
    num = int(n)        # 3  -> n이 숫자 형태가 아닌경우: ValueError
    i = 10 / num       # 4  -> num이 0일때: ZeroDivisionError
    j = i * 3              # 5
    print(j)               # 6
    print(z)               # 7 ---> NameError 
except ValueError:  #### ValueError만 처리
    # try에서 exception 발생시 처리할 코드. 
    print("숫자로 변환할 수 없는 문자열을 입력해서 실행도중 예외가 발생했습니다.")   # E-1
except ZeroDivisionError:  #### ZeroDivisionError 만 처리 # E-2
    print("0은 입력하지 마세요.")                                                 
except: ### 위에 두개 Exception을 제외한 모든 Exception을 처리. # E-3
    print("문제가 발생했어요.")                                                   
print("종료")           # 8
##3에서 ValueError발생
# 1 -> 2 -> 3(X) -> E-1 -> 8
# # 4에서 ZeroDivisionError발생
# 1 -> 2 -> 3 ->4(X) -> E-2 -> 8
# # 7에서 NameError 발생
# 1 -> 2 -> 3 -> 4-> 5 ->6 -> 7(X) -> E-3

시작
정수: 10
3.0
문제가 발생했어요.
종료

int("aaa")

ValueError Traceback (most recent call last)
Cell In[13], line 1
----> 1 int("aaa")
ValueError: invalid literal for int() with base 10: 'aaa'

10 / 0

ZeroDivisionErrorTraceback (most recent call last)
Cell In[16], line 1
----> 1 10 / 0
ZeroDivisionError: division by zero

print(z)  # 없는 변수 사용

NameError Traceback (most recent call last)
Cell In[26], line 1
----> 1 print(z) # 없는 변수 사용
NameError: name 'z' is not defined

finally 구문

예외 발생여부, 처리 여부와 관계없이 무조건 실행되는 코드블록

  • try 구문에 반드시 실행되야 하는 코드블록을 작성할때 사용한다.
  • 보통 프로그램이 외부자원과 연결해서 데이터를 주고 받는 작업을 할때 마지막 연결을 종료하는 작업을 finally 블록에 넣는다.

finally 는 except 보다 먼저 올 수 없다.

  • 구문순서
    1. try - except - finally
    2. try - except
    3. try - finally
try:
    print("1")
    print(k)
    # print(10/0)
except NameError:
    print(2)
finally:
    print("무조건")

1
2
무조건

Exception 발생 시키기¶

사용자 정의 Exception 클래스 구현

파이썬은 Exception 상황을 클래스로 정의해 사용한다.

  • Exception이 발생하는 상황과 관련된 attribute들과 메소드들을 정의한 클래스

구현

  • Exception 클래스를 상속받는다.
  • 클래스 이름은 Exception 상황을 설명할 수 있는 이름을 준다.
#잘못된 날짜(월, 일)를 입력하면 발생시킬 Exception 을 정의
class WrongDateException(Exception):
    def __init__(self, wrong_month=-1, wrong_date=-1):
        # 잘못된 월, 일을 받아서 attribute 로 저장.
        self.__wrong_month = wrong_month
        self.__wrong_date = wrong_date
    @property
    def wrong_month(self):
        return self.__wrong_month
    @property
    def wrong_date(self):
        return self.__wrong_date
    def __str__(self):
        # 에러메세지를 반환.
        return f"잘못입력한 월: {self.wrong_month}, 잘못 입력한 일: {self.wrong_date}"
e = WrongDateException(300, 200)
e.wrong_month, e.wrong_date

(300, 200)

raise 구문

Exception을 강제로 발생시킨다.

  • 업무 규칙을 어겼거나 다음 명령문을 실행할 수 없는 조건이 되면 진행을 멈추고 caller로 요청에게 작업을 처리 못했음을 알리며 돌아가도록 할때 exception을 발생시킨다.
  • 구문
    raise Exception객체

raise와 return

  • 함수나 메소드에서 return과 raise 구문이 실행되면 모두 caller로 돌아간다.
  • return은 정상적으로 끝나서 돌아가는 의미이다. 그래서 처리결과가 있으면 그 값을 가지고 돌아간다.
    - caller는 그 다음작업을 이어서 하면 된다.
  • raise는 실행도중 문제(Exception)가 생겨 비정상적으로 끝나서 돌아가는 의미이다. 그래서 비정상적인 상황 정보를 가지는 Exception객체를 반환값으로 가지고 돌아간다.
    - caller는 try - except구문으로 발생한 exception을 처리하여 프로그램을 정상화 하거나 자신도 caller에게 exception을 발생시키는 처리를 한다.
def save_month(month):
    # 월을 받아서 월을 저장하는 함수
    if month < 1 or month > 12:
        raise WrongDateException(wrong_month=month)
    else:
        print(month, "월을 저장했습니다.")
def save_date(date):
    if date < 1 or date > 31:
        raise WrongDateException(wrong_date=date)
    print(date, "일을 저장합니다.")
def save(month, date):
    try:
        save_month(month)
        save_date(date) 
        print("저장완료")
    except WrongDateException as e:   # 예외클래스 as 변수명  : 변수에 발생된 Exception객체가 대입
        print("예외발생:", e)
        print(e.wrong_month, e.wrong_date)
    print("종료")
save(10000, 7)

WrongDateExceptionTraceback (most recent call last)
Cell In[79], line 1
----> 1 save(10000, 7)
Cell In[78], line 15, in save(month, date)
13 def save(month, date):
14 # try:
---> 15 save_month(month)
16 save_date(date)
17 print("저장완료")
Cell In[78], line 4, in save_month(month)
1 def save_month(month):
2 # 월을 받아서 월을 저장하는 함수
3 if month < 1 or month > 12:
----> 4 raise WrongDateException(wrong_month=month)
5 else:
6 print(month, "월을 저장했습니다.")
WrongDateException: 잘못입력한 월: 10000, 잘못 입력한 일: -1

profile
공부 & 프로젝트 & 개발 블로그

0개의 댓글