본문 바로가기

Python

[Python] 파이썬 예외 처리 - try except else finally구문

반응형

프로그램 실행 중에 발생하는 오류를 예외(exception) 또는 런타임 오류(runtime error)라고 합니다. 실행 중에 예기치 못한 상황이 발생해서 프로그램이 죽는 상황이 발생하기도 하는데요. 프로그램이 안정적으로 구동될 수 있기 위해서는 예외 상황에 대한 처리를 잘해주어야 합니다. 파이썬에서는 예외처리를 위한 try except 구문을 제공합니다.

print("나눗셈을 위한 두 수를 입력하세요")

val_a = int(input())
val_b = int(input())

result = val_a/val_b

print("나누기 결과 : {}".format(result))

위의 코드는 두 정수를 입력받아 나머지를 출력하는 코드입니다. 하지만 위 코드는 한가지 문제가 있는데요. 바로 0으로 수를 나눴을 때의 상황입니다.

나눗셈을 위한 두 수를 입력하세요                                                                                                              
1                                                                                                                                             
0                                                                                                                                             
Traceback (most recent call last):                                                                                                            
  File "main.py", line 14, in <module>                                                                                                        
    result = val_a/val_b                                                                                                                      
ZeroDivisionError: division by zero        

위에서 보이시는 바와 같이 분모에 0이 들어가면 ZeroDivisionError 즉 0으로 나눗셈을 했을때 발생하는 예외 상황이 발생 했습니다. 이를 처리하기 위해서는 if문을 통해서 입력값을 처리할 수도 있겠습니다. 

 

if문을 통한 예외처리

print("나눗셈을 위한 두 수를 입력하세요")

val_a = int(input())
val_b = int(input())

if val_b == 0:
    print("0으로 나눌 수 없습니다.")
else:
    result = val_a/val_b
    print("나누기 결과 : {}".format(result))
나눗셈을 위한 두 수를 입력하세요                                                                                                              
1                                                                                                                                             
0                                                                                                                                             
0으로 나눌 수 없습니다.

위 처럼 발생할 수 있는 예외상황을 고려하여 조건문을 통해 처리해줄 수도 있습니다. 하지만 예외가 발생하는 상황을 예측하고 모두 조건문으로 처리하기란 쉽지 않습니다. 또한 프로그래밍의 구조적인 문제로 인하여 조건문만으로 처리불가능한 예외 상황도 있습니다. 이 떄문에 파이썬은 예외를 처리할 수 있는 구문을 제공하는데, 바로 try except 구문입니다.

 

try except 구문

try:
	예외가 발생할 수 있는 코드
except:
	예외 발생시 실행하는 코드

try except 구문의 구조는 위와 같습니다. try 블록 안에 예외가 발생할 수 있는 코드를 작성하고, 예외가 발생하면 except 블록을 실행합니다. 한번 앞서 살펴본 예제를 try except 구문으로 수정해보겠습니다.

print("나눗셈을 위한 두 수를 입력하세요")

try:
    val_a = int(input())
    val_b = int(input())
    result = val_a/val_b
    print("나누기 결과 : {}".format(result))
except:
    print("예외 상황 발생")

 문제가 발생할 가능성이 있는 나눗셈 연산 부분을 try 구문안에 넣었습니다. 이 상황에서 다시 0으로 나누는 입력을 넣어보겠습니다.

나눗셈을 위한 두 수를 입력하세요
1
0
예외 상황 발생

0으로 나누는 연산 발생시 except에 있는 코드가 실행되었습니다. try except 방법이 유용한 것은 0으로 나누는 예외 상황말고도 수많은 예외 상황들을 처리할 수 있다는 것입니다. 만약 정수가 아닌 자료형을 입력해도 예외 상황이 발생할 수 있는데요. 이러한 상황도 except에 걸려서 안정적으로 처리가능합니다.

나눗셈을 위한 두 수를 입력하세요
one
예외 상황 발생

 위 상황처럼 사용자가 정수가 아닌 문자열을 입력할때도 에러가 발생할 수 있는데, 이러한 에러도 except로 처리하는 것을 보실 수 있습니다. 

만약 except 구문에서 아무것도 처리하고 싶지 않으면 pass 키워드를 넣어주면 됩니다. 그냥 공백으로 두면 구문에러가 발생합니다.

try:
	코드
except:
	pass

 

발생한 예외상황의 이름을 알 수 있는 방법

위의 try except 구문에서는 에러 상황이 발생해도 어떤 에러가 발생했는지에 대한 종류가 나오지는 않습니다. 지금은 코드가 짧기때문에 에러가 발생해도 어떤 종류의 에러인지 유추가 가능하지만 코드가 길어지고 복잡해지면 이를 알기 어려워집니다. 이를 위해 발생한 예외의 종류를 알 수 있는 방법이 있습니다. except 부분에 아래와 같은 부분을 추가해 주면 됩니다.

except Exception as e:
    print("예외 상황 발생 : ", e)

위에서 e 값에는 예외의 종류가 담겨 있습니다. 아래와 같이 예제 코드를 수정해보고 실행하면 예외의 종류를 알 수 있습니다.

print("나눗셈을 위한 두 수를 입력하세요")

try:
    val_a = int(input())
    val_b = int(input())
    result = val_a/val_b
    print("나누기 결과 : {}".format(result))
except Exception as e:
    print("예외 상황 발생 : ", e)
나눗셈을 위한 두 수를 입력하세요
1
0
예외 상황 발생 :  division by zero

 

try except else 구문

앞서 예외 상황이 발생할 때 except 구문뒤에 코드가 실행되는 것을 확인할 수 있었습니다. 여기에 추가적으로 else 구문을 사용하면 예외가 발생하지 않았을 때 코드를 실행할 수 있습니다. 

try:
	예외 발생 가능성이 있는 코드
except :
	예외 발생 시 실행하는 코드
else: 
	예외가 발생하지 않았을 때 실행하는 코드

위 구문을 적용하여 예제를 수정해보겠습니다.

print("나눗셈을 위한 두 수를 입력하세요")

try:
    val_a = int(input())
    val_b = int(input())
    result = val_a/val_b
except Exception as e:
    print("예외 상황 발생 : ", e)
else:
    print("나누기 결과 : {}".format(result))

 예외가 발생하지 않았을 때에만 결과를 출력할 것이므로 결과 출력문을 else 부분으로 옮겼습니다. 사실 else 없이 try 구문 안에 넣어도 문제가 없습니다. 각자 스타일에 따라 else 구문을 활용하는 개발자도 있지만 필수적인 것은 아니니 참고만 하시길 바랍니다.  

 

finally 구문

예외가 발생하든 안하든 무조건 실행하는 코드 finally 구문 안에 넣습니다. 구조는 아래와 같습니다.

try:
	예외가 발생할 가능성이 있는 코드
except:
	예외 발생시 실행하는 코드
else:
	예외가 발생하지 않았을 때 실행하는 코드
finally:
	무조건 실행하는 코드

위 구조를 토대로 예제 코드를 수정해보면 아래와 같습니다.

print("나눗셈을 위한 두 수를 입력하세요")

try:
    val_a = int(input())
    val_b = int(input())
    result = val_a/val_b
except Exception as e:
    print("예외 상황 발생 : ", e)
else:
    print("나누기 결과 : {}".format(result))
finally:
    print("프로그램 종료")

finally 구문에 프로그램 종료 메시지를 넣으면 예외가 일어나는 일어나지 않든 언제든 실행됩니다. 그런데 여기서 의문이 생길 수가 있는데요. 그냥 아래와 finally 구문의 내용을 밖으로 빼면 어떻게 해서든 실행하는 데 굳이 이 구문이 필요할까라는 의문입니다. 

print("나눗셈을 위한 두 수를 입력하세요")

try:
    val_a = int(input())
    val_b = int(input())
    result = val_a/val_b
except Exception as e:
    print("예외 상황 발생 : ", e)
else:
    print("나누기 결과 : {}".format(result))

print("프로그램 종료")	# 예외가 발생하든 안하든 어떻게든 실행된다.

하지만 finally 구문은 그저 밖으로 코드를 뺴는 것과는 다른 흐름을 보일때가 있습니다. 대표적으로 아래와 같은 케이스가 있습니다.

 

try 내부에서 return 사용

def div(val_a, val_b):
    try:
        result = val_a/val_b
        return result
    except Exception as e:
        print("예외 상황 발생 : ", e)
    else:
        print("예외가 발생하지 않았습니다.")
    finally:
        print("연산 종료")
    print("div 함수의 끝")

result = div(1, 3)
print("나누기 결과 : {}".format(result))
    
연산 종료
나누기 결과 : 0.3333333333333333

나눗셈 예제를 조금 바꿔서 함수로 작성해봤습니다. 결과를 return하는 div함수인데요. finally구문은 결과를 return 시키고 나서도 실행됩니다. 하지만 try 구문 밖에 있는 "div 함수의 끝" 메시지는 출력되지 않았습니다. return문으로 인해 함수를 빠져나갔기 때문입니다.

반복문에서 break 사용시

i = 0
while True:
    try:
        print(i)
        i += 1
        if i == 3:
            break
    except:
        print("예외 상황 발생")
    finally:
        print("finally 실행")
    print("While 끝")
print("프로그램 종료")
0
finally 실행
While 끝
1
finally 실행
While 끝
2
finally 실행
프로그램 종료

while 루프 안에서 try except finally 구문을 반복할때 i가 3일때 break로 루프를 빠져나오는 코드입니다. break로 루프를 빠져나가면 맨 마지막에 있는 "while 끝"은 수행하지 않지만 finally 구문은 수행하고 종료됩니다. 이렇듯 finally 구문은 try에서 발생할 수 있는 예외상황에 대해서 어떻게든 수행하는 성질을 가지고 있기 때문에 파이썬 프로그래밍에서 자주 사용되는 구문입니다.

 

반응형