티스토리 뷰

버스를 타고 교통카드를 찍는데 단말기에서 "잔액이 부족합니다" 라고 나옵니다. 충전금액이 충분했던 것 같은데 다시 한 번 찍어봐도 여전히 "잔액이 부족합니다" 라고 나오네요. 버스는 이미 출발했고 지갑에 다른 카드는 없고 현금은 더더욱 없고 내릴수도 없고 기사님도 쳐다보고 손님들도 쳐다보고 ... 이럴 땐 어떻게 해야할까요?

 

 

이번에 공부할 내용은 예외처리입니다.

먼저 우리 실생활에서 겪을 수 있는 상황을 예로 들어보겠습니다.

 

1. 택배 기사님께서 배송중인 물건을 보니 주소가 아파트의 11층으로 되어 있는데 실제로는 10층까지만 있는 경우

2. 버스를 타고 단말기에 교통카드를 갖다댔는데 "잔액이 부족합니다" 라고 하는 경우

3. 컴퓨터에서 계산기 프로그램을 이용하려고 하는데 실수로 숫자 대신 문자를 입력 받은 경우

4. 어떤 홈페이지에 접속하려는데 주소를 잘못 적거나 사용자가 많아서 서버에 접속이 정상적으로 되지 않는 경우

 

위 각각의 경우를 만났을 때 어떻게 해야할까요?

바로 해결책이 떠오르는 경우도 있겠고 생각을 조금 해봐야하는 경우도 있을 것 같은데요. 이런 경우들처럼 예상치 못한 어떤 실책이나 실수 또는 잘못된 무언가를 에러(error) 라고 하며 에러 상황을 처리하는 것을 예외(exception) 처리라고 합니다. 가령 첫 번째 경우라면 물건을 받으실 분의 전화번호로 연락을 하여 주소를 다시 한 번 확인하는 방향으로 처리를 할 수 있겠네요.

 

프로그램에서는 굉장히 많은 에러 상황이 발생할 수 있으며 이를 어떻게 처리하느냐에 따라 완성도가 높고 사용성이 좋은 프로그램이 되거나 또는 갑자기 응답 없음 상태로 있다가 강제 종료되어 지금까지 하던 모든 작업이 수포로 돌아가는 프로그램이 될 수도 있습니다. 

 

설명을 돕기 위해 사용자로부터 두 개의 수를 입력받아서 나누기를 해주는 아주 간단한 계산기 프로그램을 만들어보겠습니다.

print("나누기 전용 계산기입니다.")
num1 = int(input("첫 번째 숫자를 입력하세요 : "))
num2 = int(input("두 번째 숫자를 입력하세요 : "))
print("{0} / {1} = {2}".format(num1, num2, int(num1/num2)))

 

프로그램을 실행하고 순서대로 6 과 3 을 입력하면 계산 결과가 다음과 같이 2 라고 잘 출력됩니다.

나누기 전용 계산기입니다.
첫 번째 숫자를 입력하세요 : 6
두 번째 숫자를 입력하세요 : 3
6 / 3 = 2

 

그런데 만약 숫자가 아닌 문자를 입력하면 어떨까요? 프로그램을 다시 한 번 실행시키고 이번에는 6 과 "삼" 을 입력해보겠습니다.

첫 번째 숫자를 입력하세요 : 6
두 번째 숫자를 입력하세요 : 삼
Traceback (most recent call last):
  File "파일경로", line 3, in <module>
    num2 = int(input("두 번째 숫자를 입력하세요 : "))
ValueError: invalid literal for int() with base 10: '삼'

처음 6 을 입력했을 땐 괜찮았는데 "삼" 을 입력하고 나니 에러 메시지가 출력되면서 프로그램이 종료됩니다. 코드에서는 입력받은 값을 int( ) 로 감싸서 정수형으로 변환을 해야 하는데 "삼" 은 정수로 변환을 할 수가 없는 문자라서 발생하는 에러입니다.

 

에러에 대한 예외 처리는 다음과 같은 형태로 작성합니다.

try:
    실행 명령문1
    실행 명령문2
    ...
except 에러 종류1:
    예외 처리 명령문1
    예외 처리 명령문2
    ...
except 에러 종류2:
    예외 처리 명령문1
    예외 처리 명령문2
    ...

 

앞에서 발생한 에러 메시지 중 마지막 문장을 보면 ValueError 라는 에러 종류와 함께 자세한 메시지가 출력되고 있습니다.

ValueError: invalid literal for int() with base 10: '삼'

 

ValueError 는 이름에서 유추할 수 있듯이 값이 잘못되어서 발생하는 에러인데 이에 대한 예외처리를 적용하도록 해보겠습니다. 먼저 실행하려는 코드 위에 try: 를 적고 하위 코드들은 모두 들여쓰기를 해줍니다. 그리고 밑에서 except 뒤에 어떤 에러에 대한 처리인지를 명시해줍니다. 여기서는 ValueError 에 대한 처리가 되며, 다음 줄부터 들여쓰기를 한 뒤 예외 처리 명령문을 적으면 되는데요. 이렇게 코드를 작성하면 try 와 except 사이에서 실행되는 명령문 중에서 ValueError 가 발생하는 경우 except ValueError: 부분의 코드가 실행되고 나서 프로그램은 계속하여 실행됩니다. 만약 아무 에러가 발생하지 않는다면 except 부분은 실행이 되지 않고 넘어가게 되지요.

try:
    print("나누기 전용 계산기입니다.")
    num1 = int(input("첫 번째 숫자를 입력하세요 : "))
    num2 = int(input("두 번째 숫자를 입력하세요 : "))
    print("{0} / {1} = {2}".format(num1, num2, int(num1/num2)))
except ValueError:
    print("에러! 잘못된 값을 입력하였습니다.")

코드를 실행시키고 6 과 3 을 순서대로 입력하면 예외처리를 하기 전과 동일한 결과가 나옵니다.

나누기 전용 계산기입니다.
첫 번째 숫자를 입력하세요 : 6
두 번째 숫자를 입력하세요 : 3
6 / 3 = 2

 

다시 한 번 실행시키고 6 과 "삼"이라고 적어볼까요?

나누기 전용 계산기입니다.
첫 번째 숫자를 입력하세요 : 6
두 번째 숫자를 입력하세요 : 삼
에러! 잘못된 값을 입력하였습니다.

이번에는 알아보기 어려운 에러메시지 대신 except ValueError: 부분의 print() 문이 실행되는 것을 확인할 수 있습니다.

 

하지만 이것으로 예외처리가 끝난 것은 아닙니다.

프로그램을 다시 한 번 실행시키고 6 과 0 을 적어보겠습니다.

나누기 전용 계산기입니다.
첫 번째 숫자를 입력하세요 : 6
두 번째 숫자를 입력하세요 : 0
Traceback (most recent call last):
  File "파일경로", line 5, in <module>
    print("{0} / {1} = {2}".format(num1, num2, int(num1/num2)))
ZeroDivisionError: division by zero

 

그랬더니 새로운 에러인 ZeroDivisionError 가 나오면서 메시지가 출력됩니다. 모든 수는 0 으로 나눌 수 없는데 두 번째 값으로 0 을 넣어서 발생하는 오류이지요.

 

이렇게 서로 다른 종류의 에러에 대해 각각 처리하려면 except 구문을 추가하여 작성하면 됩니다. 앞의 코드에 추가하여 ZeroDivisionError 에 대한 예외처리를 추가하는데 이번에는 에러 뒤에 as 구문을 이용하여 err 이라는 이름을 통해 에러 메시지를 직접 출력해보겠습니다. 

try:
    print("나누기 전용 계산기입니다.")
    num1 = int(input("첫 번째 숫자를 입력하세요 : "))
    num2 = int(input("두 번째 숫자를 입력하세요 : "))
    print("{0} / {1} = {2}".format(num1, num2, int(num1/num2)))
except ValueError:
    print("에러! 잘못된 값을 입력하였습니다.")
except ZeroDivisionError as err:
    print(err)

 

프로그램을 실행하고 6 과 0 을 입력해보니 다음과 같이 결과가 출력됩니다.

나누기 전용 계산기입니다.
첫 번째 숫자를 입력하세요 : 6
두 번째 숫자를 입력하세요 : 0
division by zero

 

사용자로부터 값을 입력받는 과정에서 ZeroDivisionError 가 발생했고 예외처리를 통해서 except ZeroDivisionError 부분이 실행되었는데 우리가 직접 정의하지 않은 division by zero 라는 문구가 출력되었네요.

 

알고 보니 이는 예외처리 전에 발생한 에러 메시지 중 ZeroDivisionError: 뒤에 나오는 메시지가 그대로 출력된 것이었습니다.

Traceback (most recent call last):
  File "파일경로", line 5, in <module>
    print("{0} / {1} = {2}".format(num1, num2, int(num1/num2)))
ZeroDivisionError: division by zero

 

이와 같이 에러의 종류에 따라 쉽게 알아볼 수 있는 메시지가 제공되는 경우 코드에서 별도로 에러 메시지를 정의하지 않고도 간편하게 예외처리를 할 수 있습니다.

 

 

 

이번에는 코드를 많이 바꿔보겠습니다. 두 개의 수를 입력받는건 동일한데 입력받은 수를 nums 라는 리스트에 추가를 하고 이어서 계산 결과까지 리스트에 추가한 뒤에 print() 를 통해서 리스트의 값 3개를 순서대로 출력하겠습니다.

try:
    print("나누기 전용 계산기입니다.")
    nums = []
    nums.append(int(input("첫 번째 숫자를 입력하세요 : ")))
    nums.append(int(input("두 번째 숫자를 입력하세요 : ")))
    nums.append(int(nums[0] / nums[1])) # 계산 결과를 리스트에 추가
    print("{0} / {1} = {2}".format(nums[0], nums[1], nums[2]))
except ValueError:
    print("에러! 잘못된 값을 입력하였습니다.")
except ZeroDivisionError as err:
    print(err)

 

프로그램 실행 후에 6 과 3 을 순서대로 입력하면 결과가 잘 출력되는 것을 볼 수 있습니다.

나누기 전용 계산기입니다.
첫 번째 숫자를 입력하세요 : 6
두 번째 숫자를 입력하세요 : 3
6 / 3 = 2

 

그런데 만약에 계산 결과를 리스트에 추가하는 부분을 깜빡했다면 어떨까요? 아래와 같이 임시로 주석처리를 해보겠습니다.

try:
    print("나누기 전용 계산기입니다.")
    nums = []
    nums.append(int(input("첫 번째 숫자를 입력하세요 : ")))
    nums.append(int(input("두 번째 숫자를 입력하세요 : ")))
    # nums.append(int(nums[0] / nums[1])) # 계산 결과를 리스트에 추가
    print("{0} / {1} = {2}".format(nums[0], nums[1], nums[2]))
except ValueError:
    print("에러! 잘못된 값을 입력하였습니다.")
except ZeroDivisionError as err:
    print(err)

 

실행 후에 동일하게 6 과 3 을 입력해보니 이번에는 또 새로운 에러가 발생합니다.

나누기 전용 계산기입니다.
첫 번째 숫자를 입력하세요 : 6
두 번째 숫자를 입력하세요 : 3
Traceback (most recent call last):
  File "파일경로", line 38, in <module>
    print("{0} / {1} = {2}".format(nums[0], nums[1], nums[2]))
IndexError: list index out of range

 

IndexError 와 함께 에러 메시지가 출력되는데 그 이유는 현재 리스트에는 두 개의 수만 들어있으므로 index 기준으로는 [0], [1] 만 접근 가능한데 [2] 에 접근하려고 하니 사용 가능한 리스트의 범위를 벗어나서 발생하는 에러입니다.

 

이번에도 IndexError 구문을 추가할 수도 있겠지만 이런 식으로 모든 에러에 대한 처리를 다 해주기는 어려운 경우도 있습니다. 이 때는 다음과 같이 코드 마지막에 except Exception as err: 구문을 추가함으로써 지금까지 정의되지 않은 모든 에러에 대한 처리가 가능합니다.

try:
    print("나누기 전용 계산기입니다.")
    nums = []
    nums.append(int(input("첫 번째 숫자를 입력하세요 : ")))
    nums.append(int(input("두 번째 숫자를 입력하세요 : ")))
    # nums.append(int(nums[0] / nums[1])) # 계산 결과를 리스트에 추가
    print("{0} / {1} = {2}".format(nums[0], nums[1], nums[2]))
except ValueError:
    print("에러! 잘못된 값을 입력하였습니다.")
except ZeroDivisionError as err:
    print(err)
except Exception as err:
    print("알 수 없는 에러가 발생하였습니다.")
    print(err)

 

코드 실행 후 다시 한 번 6 과 3 을 입력해보면 다음과 같이 예외처리가 되는 것을 확인할 수 있습니다. 

나누기 전용 계산기입니다.
첫 번째 숫자를 입력하세요 : 6
두 번째 숫자를 입력하세요 : 3
알 수 없는 에러가 발생하였습니다.
list index out of range

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함