파이썬 예외처리(try except, else finally, raise), 예외 만들기

Yeonu·2020년 11월 24일
0

Python 이론

목록 보기
23/30
post-thumbnail

예외 처리는 에러가 발생하더라도 스크립트의 실행을 중단하지 않고 계속 실행하고자 할 때 사용한다.


👉try except 사용하기

try에 실행할 코드를 넣고 except에 예외가 발생했을 때 처리하는 코드를 넣는다.

다음은 10을 어떤 수로 나누는 함수다. 0을 넣어 ZeroDivisionError 예외가 발생했다.

>>> ten_div(0)
Traceback (most recent call last):
  File "<pyshell#121>", line 1, in <module>
    ten_div(0)
  File "<pyshell#119>", line 2, in ten_div
    return 10 / x
ZeroDivisionError: division by zero 

위 코드에 예외 처리를 사용했다.

try:
    x = int(input('나눌 숫자를 입력하세요: '))
    y = 10 / x
    print(y)
except:    # 예외가 발생했을 때 실행됨
    print('예외가 발생했습니다.')
    
# 실행 결과
나눌 숫자를 입력하세요: 0 (입력)
예외가 발생했습니다.

예외가 발생하면 해당 줄에서 코드 실행을 중단하고 바로 except로 가서 코드를 실행한다. 즉, try의 y = 10 / x를 비롯하여 그 아래줄에 있는 print(y)도 실행되지 않는다.


👉특정 예외만 처리하기

try:
  실행할 코드
except 예외이름:
  예외가 발생했을 때 처리하는 코드
  
  
ex)
y = [10, 20, 30]

try:
  index, x = map(int, input('인덱스와 나눌 숫자를 입력하세요: ').split())
  print(y[index] / x)
except ZeroDivisionError:    # 숫자를 0으로 나눠서 에러가 발생했을 때 실행됨
  print('숫자를 0으로 나눌 수 없습니다.')
except IndexError:           # 범위를 벗어난 인덱스에 접근하여 에러가 발생했을 때 실행됨
  print('잘못된 인덱스입니다.')
  
# 실행 결과
인덱스와 나눌 숫자를 입력하세요: 2 0 (입력)
숫자를 0으로 나눌 수 없습니다.

# 다른 예외
인덱스와 나눌 숫자를 입력하세요: 3 5 (입력)
잘못된 인덱스입니다.



👉예외의 에러 메시지 받아오기

코드의 except에 as e를 넣는다. 보통 예외( exception)의 e를 따서 변수 이름을 e로 짓는다.

try_except_as.py

y = [10, 20, 30]

try:
   index, x = map(int, input('인덱스와 나눌 숫자를 입력하세요: ').split())
   print(y[index] / x)
except ZeroDivisionError as e:      # as 뒤에 변수를 지정하면 에러를 받아옴
   print('숫자를 0으로 나눌 수 없습니다.', e)    # e에 저장된 에러 메시지 출력
except IndexError as e:
   print('잘못된 인덱스입니다.', e)
   
#실행 결과
인덱스와 나눌 숫자를 입력하세요: 2 0 (입력)
숫자를 0으로 나눌 수 없습니다. division by zero

#실행 결과
인덱스와 나눌 숫자를 입력하세요: 3 5 (입력)
잘못된 인덱스입니다. list index out of range



👉else와 finally 사용하기

else는 예외가 발생하지 않았을 때 코드를 실행하며 finally는 예외 발생 여부와 상관없이 항상 코드를 실행한다.
else는 except 바로 다음에 와야 하며 except를 생략할 수 없으나 finally는 except와 else를 생략할 수 있다.

try:
   실행할 코드
except:
   예외가 발생했을 때 처리하는 코드
else:
   예외가 발생하지 않았을 때 실행할 코드
finally:
   예외 발생 여부와 상관없이 항상 실행할 코드



👉raise로 예외 발생시키기

예외를 발생시킬 때는 raise에 예외를 지정하고 에러 메시지를 넣는다(에러 메시지는 생략 할 수 있음).

raise 예외('에러메시지')

    x = int(input('3의 배수를 입력하세요: '))
    if x % 3 != 0:                                 # x가 3의 배수가 아니면
        raise Exception('3의 배수가 아닙니다.')    # 예외를 발생시킴
    print(x)
except Exception as e:                             # 예외가 발생했을 때 실행됨
    print('예외가 발생했습니다.', e)


#실행 결과
3의 배수를 입력하세요: 5 (입력)
예외가 발생했습니다. 3의 배수가 아닙니다.

raise로 예외를 발생시키면 raise 아래에 있는 코드는 실행되지 않고 바로 except로 넘어간다.
따라서 try의 print(x)는 실행되지 않는다.



👉raise의 처리 과정

함수 안에서 raise를 사용하지만 함수 안에는 try except가 없는 상태다.

def three_multiple():
   x = int(input('3의 배수를 입력하세요: '))
   if x % 3 != 0:                             # x가 3의 배수가 아니면
       raise Exception('3의 배수가 아닙니다.')  # 예외를 발생시킴
   print(x)                          # 현재 함수 안에는 except가 없으므로
                                     # 예외를 상위 코드 블록으로 넘김

try:
   three_multiple()
except Exception as e:               # 하위 코드 블록에서 예외가 발생해도 실행됨
   print('예외가 발생했습니다.', e)


#실행 결과
3의 배수를 입력하세요: 5 (입력)
예외가 발생했습니다. 3의 배수가 아닙니다.

예외가 발생하더라도 현재 코드 블록에서 처리해줄 except가 없다면 except가 나올 때까지 계속 상위 코드 블록으로 올라간다.

만약 함수 바깥에도 처리해줄 except가 없다면 코드 실행은 중지되고 에러가 표시된다.



👉현재 예외를 다시 발생시키기

try except에서 처리한 예외를 다시 발생시키는 방법이다. except 안에서 raise를 사용하면 현재 예외를 다시 발생시킨다(re-raise).

def three_multiple():
    try:
        x = int(input('3의 배수를 입력하세요: '))
        if x % 3 != 0:              		# x가 3의 배수가 아니면
            raise Exception('3의 배수가 아닙니다.')  # 예외를 발생시킴
        print(x)
    except Exception as e:              	# 함수 안에서 예외를 처리함
        print('three_multiple 함수에서 예외가 발생했습니다.', e)
        raise   # raise로 현재 예외를 다시 발생시켜서 상위 코드 블록으로 넘김

try:
    three_multiple()
except Exception as e:                # 하위 코드 블록에서 예외가 발생해도 실행됨
    print('스크립트 파일에서 예외가 발생했습니다.', e)


#실행 결과
3의 배수를 입력하세요: 5 (입력)
three_multiple 함수에서 예외가 발생했습니다. 3의 배수가 아닙니다.
스크립트 파일에서 예외가 발생했습니다. 3의 배수가 아닙니다.



  • assert로 예외를 발생시킬 수도 있다. assert는 디버깅 모드에서만 실행된다.



👉예외 만들기

Exception을 상속받아서 새로운 클래스를 만들고 __init__ 메서드에서 기반 클래스의 __init__ 메서드를 호출하면서 에러 메시지를 넣어주면 된다.

class 예외이름(Exception):
    def __init__(self):
        super().__init__('에러메시지')



ex)
class NotThreeMultipleError(Exception):  # Exception을 상속받아 새로운 예외 만듦
    def __init__(self):
        super().__init__('3의 배수가 아닙니다.')

def three_multiple():
    try:
        x = int(input('3의 배수를 입력하세요: '))
        if x % 3 != 0:                    # x가 3의 배수가 아니면
            raise NotThreeMultipleError   # NotThreeMultipleError 예외를 발생시킴
        print(x)
    except Exception as e:
        print('예외가 발생했습니다.', e)

three_multiple()


#실행 결과
3의 배수를 입력하세요: 5 (입력)
예외가 발생했습니다. 3의 배수가 아닙니다.

위에서는 __init__ 메서드를 만들면서 에러 메세지를 넣었지만 pass를 넣어 구현하지 않고, 발생시킬 때 에러 메세지를 넣어줘도 된다.

class NotThreeMultipleError(Exception):   # Exception만 상속받고
    pass                                  # 아무것도 구현하지 않음


raise NotThreeMultipleError('3의 배수가 아닙니다.')   
# 예외를 발생시킬 때 에러 메시지를 넣음




출처, 강의
💡 38.1 ~
💡 38.4

0개의 댓글