본문 바로가기

Python_programming/초중급편

파이썬 '예외 처리' 기본 개념

파이썬에서 '예외 처리'에 대한 방법을 정리해보겠습니다. 

'파이썬 코딩 도장 Unit 38. 예외처리 사용하기' 내용을 예시 코드와 설명까지 대부분 따라하고 있으니 참고해주세요. (공부하면서 알게되어 추가된 내용 있음 - raise 부분)

'파이썬 코딩 도장 Unit 38. 예외처리 사용하기' 링크는 맨 아래 첨부했으니, 이 포스트를 한 번 훏어보고 넘어가셔서 공부하면 더 좋습니다 :)

 

1. try except

 

-기본 틀: 1.1 -

 

try:

    실행할 코드

except:

    예외가 발생했을 때 처리하는 코드

 

 

예시 코드

try:
    x = int(input('나눌 숫자를 입력하세요: '))
    y = 10 / x
    print(y)
except:
    print('예외가 발생했습니다.')

기본 틀에서 나온대로 try 문은 그대로 실행이 되다가 에러가 발생하는 부분에서 막히게 됩니다. 

 

input 으로 '0'을 주게 되면 3번째 라인에서 에러가 발생하게 되고, except 구문으로 넘어갑니다.

 

 

-코드-

(아래 설명 참고)

 

참고: https://dojang.io/mod/page/view.php?id=2398 

 

1.1 '특정 예외'만 처리하기

 

좀전에는 except 다음에 예외이름을 안 적어놓았습니다. 이럴 경우, 모든 예외를 다 받아서 처리한다는 의미입니다. 

하지만, 여러 코드들에서는 특정 예외만을 지정해서 처리하도록 많이 하는데요.

특정 예외만 처리하도록 바꿔보겠습니다.

 

-기본 틀: 1.1 -

 

try:

    실행할 코드

except 예외이름:

    예외가 발생했을 때 처리하는 코드

 

 

-코드-

y = [10,20,30]

try:
    index, x = map(int,input('인덱스와 나눌 숫자를 입력: ').split())
    print(y[index] / x )
except ZeroDivisionError:
    print('숫자를 0으로 나눌 수 없습니다.')
except IndexError:
    print('잘못된 인덱스입니다.')

 

 

-실행 결과-

 

 

 

1.2 예외 에러메시지' 받아오기

 

보통 "as 변수" 는 별명으로 긴 이름을 줄여서 사용할 때 import 문에서 많이 사용합니다.

except 구문에 이를 적용하면 발생하는 "에러 메시지"를 별명에 집어넣게 되고, 이를 받아올 수 있습니다.

 

-기본 틀: 1.2 -

 

try:

    실행할 코드

except 예외이름 as 변수:

    예외가 발생했을 때 처리하는 코드

 

 

-코드-

y = [10,20,30]

try:
    index, x = map(int,input('인덱스와 나눌 숫자를 입력: ').split())
    print(y[index] / x )
except ZeroDivisionError as e:
    print('숫자를 0으로 나눌 수 없습니다.' , e)
except IndexError as e:
    print('잘못된 인덱스입니다.' , e)

 

-실행 결과- 

 

except 에서 "as e" 라는 구문을 추가해서 에러 메시지를 받아왔고, print 문에 e 변수를 넣어주면 에러 메시지가 출력됨을 확인할 수 있습니다.

 

 

2. else : "예외가 발생하지 않았을 때" 코드 실행

 

try excpe 구문에서 else 를 적용하게 되면 "예외가 발생하지 않았을 때" else 구문의 코드를 실행합니다.

 

-기본 틀2 -

 

try:

    실행할 코드

except:

    예외가 발생했을 때 처리하는 코드

else:

    예외가 발생하지 않았을 때 실행할 코드

 

- 코드 - 

try:
    x = int(input('나눌 숫자를 입력: '))
    y = 10 / x
except ZeroDivisionError: # 숫자를 0으로 나눠서 에러가 발생했을 때 실행됨 
    print('숫자를 0으로 나눌 수 없습니다.')
else:   # try 의 코드에서 예외가 발생하지 않았을 때 실행됨
    print(y)

 

- 실행 결과 - 

 

 

2.1 finally : "예외와는 상관없이 항상" 코드 실행

 

try excpe 구문에서 else 를 적용하게 되면 "예외가 발생하지 않았을 때" else 구문의 코드를 실행합니다.

 

-기본 틀2 -

 

try:

    실행할 코드

except:

    예외가 발생했을 때 처리하는 코드

else:

    예외가 발생하지 않았을 때 실행할 코드

finally:

    예외 발생 여부가 상관없이 항상 실행할 코드

 

- 코드 -

try:
    x = int(input('나눌 숫자를 입력하세요: '))
    y = 10 / x
except ZeroDivisionError:
    print('숫자를 0으로 나눌 수 없습니다.')
else:
    print(y)
finally:
    print('코드 실행이 끝났습니다.')

- 결과- 

 

 

 참고: https://dojang.io/mod/page/view.php?id=2399

 

 

3. 예외 발생시키기

 

파이썬에서 (모든) 예외를 처리하는 것(=특정 예외 지정하지 않음) 과 특정 예외를 처리하는 방법, 그리고 예외의 발생 유무에 따른 구문들(else , finally) 등을 살펴봤습니다. 이번에는 직접 예외를 발생시켜 보겠습니다.

 

- 기본 틀 -

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

 

- 코드 - 

try:
    x = int(input('3의 배수를 입력하세요: '))
    if x % 3 != 0:
        raise Exception('3의 뱃수가 아닙니다.')
    print(x)
except Exception as e:
    print('예외 발생', e)

 

raise 로 예외가 발생되면, raise 아래에 있는 print(x) 코드는 실행되지 않고, except 구문으로 넘어갑니다.

예시 코드에서는 Exception 

 

- 결과 -

 

 

- raise 문 보충 설명 - 

 

In [15]:  raise 문은 프로그래머가 지정한 예외가 발생하도록 강제할 수 있게 합니다. 

 

In [21]: 만약 예외가 발생했는지는 알아야 하지만 처리하고 싶지는 않다면, 더 간단한 형태의 raise 문이 그 예외를 다시 일으킬 수 있게 합니다:

 

 

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

 

except 안에서 raise 를 사용하면 현재 예외를 다시 발생시킵니다.(re-raise)

 

- 기본 틀 -

 

except Exception as e:

    raise 

 

 

-코드-

 

def three_multiple():
    try:
        x = int(input('3의 배수를 입력하세요: '))
        if x % 3 != 0:
            raise Exception('3의 배수가 아닙니다.')
        print(x)
    except Exception as e:
        print('three multiple 함수에서 예외가 발생했습니다.', e)
        raise

 

- 결과 - 

 

 

우선, 함수 안에서 excpet 구문이 한 번 실행되는데, 마지막이 raise 로 끝납니다. 이 때, 예외는 한 번 더 발생이 됐고, 이는 바깥에 있는 상위 코드 블록으로 넘어갑니다. 상위 코드 블록에 있는 except 구문이 다시 실행이 되게 됩니다. 만약에 함수 안에 except 구문에 raise 가 없으면 어떻게 될까요? 

 

- 결과2 : raise 없을때 -

 

 

 

 

raise 구문을 주석처리하고 실행하면 상위코드 블록(In[23]) 에서 except 가 실행되지 않습니다. 이미 try 구문 안에 함수가 실행되면 그 안에서 except 문으로 발생된 예외를 처리했기 때문입니다. 즉, 상위코드 블록의 exception 은 이미 처리게 되었기에 처리할 예외가 없는 상황이 놓이게 된 셈입니다. 예외가 없다는 걸 else 구문을 넣어보면 알 수 있습니다. (아래 코드 참고)

 

 

 

앞에서 else 구문은 예외가 없을 때 실행된다고 배웠습니다. 헌데, 함수 내에서 예외가 발생됐고 , 처리가 되었기에 상위 코드 블록에서 예외가 당연히 발생하지 않았습니다. 그러므로, else 구문이 실행되는 것을 확인할 수 있습니다. 

 

+) assert 로 예외 발생시키기

 

assert 는 지정된 조건식이 거짓일 때 AssertionError 예외를 발생시키며 조건식이 참이면 그냥 넘어갑니다.

보통 assert 는 나와서는 안되는 조건을 검사할 때 사용합니다.

assert 조건식

assert 조건식 ,  에러메시지

 

-코드-

 

x = int(input('3의 배수를 입력하세요: '))
assert x % 3 == 0, '3의 배수가 아닙니다.'
print(x)

 

-결과-

 

 

-추가 설명- 

 

왜 assert가 필요한 것일까?

어떤 함수는 성능을 높이기 위해 반드시 정수만을 입력받아 처리하도록 만들 수 있다. 이런 함수를 만들기 위해서는 반드시 함수에 정수만 들어오는지 확인할 필요가 있다. 이를 위해 if문을 사용할 수도 있고 '예외 처리'를 사용할 수도 있지만 '가정 설정문'을 사용하는 방법도 있다. 아래 코드는 함수 인자가 정수인지 확인하는 코드이다.

 

 

lists에 실수가 하나 있으므로 AssertionError가 발생했다. assert 문은 다음 형식으로 작동한다.

assert 조건, '메시지'

 

'메시지'는 생략할 수 있다.

assert는 개발자가 프로그램을 만드는 과정에 관여한다. 원하는 조건의 변수 값을 보증받을 때까지 assert로 테스트 할 수 있다.

이는 단순히 에러를 찾는것이 아니라 값을 보증하기 위해 사용된다.

예를 들어 함수의 입력 값이 어떤 조건의 참임을 보증하기 위해 사용할 수 있고 함수의 반환 값이 어떤 조건에 만족하도록 만들 수 있다. 혹은 변수 값이 변하는 과정에서 특정 부분은 반드시 어떤 영역에 속하는 것을 보증하기 위해 가정 설정문을 통해 확인 할 수도 있다.

 

이처럼 실수를 가정해 값을 보증하는 방식으로 코딩 하기 때문에 이를 '방어적 프로그래밍'이라 부른다.

 

- 다음 예제 -

 

사용자 입력(예: 웹 양식 같은 것을 통해 입력한 데이터)을 검사하는 데 assert를 사용하면 안 된다. 내부적인 점검과 불변 조건(항상 참인 조건)을 검사하는 것이 목적이다.

 

계약 프로그래밍(Contract Programming)

assert를 아낌없이 활용하는 소프트웨어 설계 접근법으로, 계약에 의한 설계(Design By Contract)라고도 한다. 소프트웨어 설계자가 소프트웨어 구성요소의 정확한 인터페이스 사양을 정의해야 한다고 규정한다.

예를 들어, 함수의 모든 입력에 assert를 넣을 수 있다.

 

입력값 검사는 적절한 인자를 사용하지 않은 호출자를 즉시 잡아낸다.

 

4. 예외 만들기

 

내장된 예외를 처리했는데 직접 만들어서 처리하는 방법은 아래 기본틀을 참고하시면 됩니다. 

Exception 읃 상속받아서 새로운 클래스를 만드는데 이 때, __init__ 메서드에 '에러 메시지'를 넣어주면 됩니다.

 

-기본 틀 -

 

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

 

- 코드 -

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

 

 

- 결과 - 

 

 

이상 파이썬에서 '예외 처리'에 대한 기본 내용을 정리해보았습니다 :)

 

 

# 참고 #

 

https://dojang.io/mod/page/view.php?id=2398 

 

파이썬 코딩 도장: 38.1 try except로 사용하기

Unit 38. 예외 처리 사용하기 예외(exception)란 코드를 실행하는 중에 발생한 에러를 뜻합니다. 다음과 같이 10을 어떤 값으로 나누는 함수 ten_div가 있을 때 인수에 따라 정상으로 동작하기도 하고 에

dojang.io

https://docs.python.org/ko/3/tutorial/errors.html

 

8. 에러와 예외 — Python 3.9.5 문서

8. 에러와 예외 지금까지 에러 메시지가 언급되지는 않았지만, 예제들을 직접 해보았다면 아마도 몇몇 개를 보았을 것입니다. (적어도) 두 가지 구별되는 에러들이 있습니다; 문법 에러 와 예외.

docs.python.org

https://wikidocs.net/21050

 

위키독스

온라인 책을 제작 공유하는 플랫폼 서비스

wikidocs.net

https://wikidocs.net/84431

 

위키독스

온라인 책을 제작 공유하는 플랫폼 서비스

wikidocs.net