[Programming Language]/[Python]

[Python] :: 예외 처리 - syntax error, runtime error(exception), 조건문 예외 처리, try 구문 예외 처리

Semincolon 2023. 7. 7. 23:09

◎ 파이썬에서의 오류(error)

  파이썬을 비롯한 프로그래밍 언어에서 오류는 크게 2가지로 나누어 볼 수 있다.

  • 구문 오류(syntax error) : 프로그램 실행 전에 발생하는 오류
  • 런타임 오류(runtime error) 또는 예외(exception) : 프로그램 실행 중에 발생하는 오류

1) 구문 오류

  구문 오류란 문법적인 부분에서 발생하는 오류를 말한다. 괄호의 개수, 들여쓰기, 따옴표의 개수 불일치 등으로 인해 프로그램이 실행되기도 전에 발생하는 오류이다.

# 따옴표 개수 불일치
print("Hello)

2) 런타임 오류 or 예외

  런타임 오류 또는 예외란 프로그램이 실행되는 도중에 발생하는 오류이다. 선언되지 않은 변수의 사용이나 리스트의 범위를 벗어난 인덱스에 접근하는 경우 등에 발생한다.

# 리스트 범위 초과 접근
num_list = [1, 2, 3, 4, 5]
for i in range(6):
    print(num_list[i])


◎ 예외 처리(exception handling)

  구문 오류가 아닌 예외(런타임 오류)를 처리하는 것을 예외 처리(exception handling)라고 한다. 참고로 구문 오류는 프로그램이 실행되기도 전에 발생하는 오류이므로 예외 처리 방법처럼 처리할 수는 없다. 예외 처리 방법에는 두 가지가 있다.

  • 조건문(if)을 사용하는 방법
  • try~except 구문을 사용하는 방법

1) 조건문(if)을 사용한 예외 처리

input_value = input()

# 입력한 값이 정수일 경우에만 가능
print(int(input_value))

<정수 입력>
<문자열 입력>

  위 코드는 입력받은 값을 정수형으로 출력하는 코드이다. 당연히 정수를 입력하면 문제가 발생하지 않지만 정수가 아닌 데이터를 입력하게 되면 예외가 발생한다. 위 경우에서는 ValueError가 발생하였다. 그렇다면 위 상황처럼 예외가 발생하는 경우를 고려하여 조건문으로 처리해보겠다.

input_value = input()

# 조건문을 사용한 예외 처리
if input_value.isdigit():
    print(int(input_value))
else:
    print("Not Integer Type Value")

  이처럼 조건문을 사용하여 발생할 예외를 처리해주면 정수형이 아닌 데이터가 입력되었더라도 프로그램이 강제로 종료되지 않고 정상적으로 종료될 수 있게 된다.

 

2) try~except 구문을 사용한 예외 처리

  try~except 구문은 조건문을 사용한 예외 처리보다 훨씬 더 사용하기 편리하다. 기본적인 구조는 아래와 같다.

try:
	예외가 발생할 가능성이 있는 코드
except:
	예외가 발생했을 때 실행할 코드
else:
	예외가 발생하지 않았을 때 실행할 코드
finally:
	예외 발생 여부에 관계없이 실행할 코드

  try 구문은 절대 단독으로는 사용될 수 없고 반드시 except나 finally와 함께 사용되어야 한다. 사용 가능한 조합은 아래와 같다.

  • try + except
  • try + except + else
  • try + except + finally
  • try + except + else + finally
  • try + finally

  위 조합은 반드시 나열한 순서대로 사용해야 하며 만약 else가 except보다 앞에 오는 것처럼 순서가 바뀐다면 오류가 발생하게 된다. 위에서 다루었던 예외가 발생할 가능성이 있는 코드를 이번에는 try ~ except 구문을 사용하여 처리해보자.

input_value = input()

# try~except 구문을 사용한 예외 처리
try:
    print(int(input_value))
except:
    print("Not Integer Type Value")

  조건문을 사용한 예외 처리와 동일하게 정수가 아닌 데이터를 입력한 경우에는 except 부분의 코드가 실행되는 것을 확인할 수 있다. 만약 오류가 발생해도 일단 별도의 처리는 하지 않되, 프로그램의 강제 종료를 막기 위해선 except 부분에 pass 키워드를 넣어주면 된다.

input_value = input()

# try~except 구문을 사용한 예외 처리
try:
    print(int(input_value))
except:
    pass

  이번에는 else 구문도 함께 사용하여 예외 처리를 해보자. else 구문은 예외가 발생하지 않고 정상적으로 실행이 됐을 때 실행되는 코드이다.

input_value = input()

# try~except 구문을 사용한 예외 처리
try:
    print(int(input_value))
except:
    print("Not Integer Type Value")
else:
    print("Integer Type Value")

  else 구문을 추가함으로써 정수(123)가 입력되어 프로그램이 정상적으로 실행되었다는 것을 출력문을 통해 확인할 수 있게 되었다. 이제 마지막으로 finally 구문도 추가하여 예외 처리를 해보자.

input_value = input()

# try~except 구문을 사용한 예외 처리
try:
    print(int(input_value))
except:
    print("Not Integer Type Value")
else:
    print("Integer Type Value")
finally:
    print("Exit program")

<정수 입력>
<문자열 입력>

  finally 구문을 통해 예외가 발생하지 않고 정상적으로 실행이 된 경우와 예외가 발생한 경우에도 모두 실행될 공통적인 코드를 삽입할 수 있게 되었다.

 

2-1) try 구문 내부 return 키워드

  try 구문 내부에 return 키워드가 있다면 바로 실행이 종료될까? 아래 코드를 통해 확인해보자.

def print_n(n):
    try:
        # 매개변수를 정수형으로 출력
        print(int(n))
        return
        print("After return")
    except:
        print("예외 발생")
    else:
        print("정상 실행")
    finally:
        print("print_n() 종료")

print_n(3)
print()

print_n('abc')

  print_n() 함수는 매개변수를 정수형으로 출력하는 코드로써 매개변수가 정수형이 아닌 경우에는 예외가 발생한다. 매개변수로 3이 전달된 경우에는 정상적으로 출력이 됐지만 return 이후의 코드는 실행이 되지 않는 것을 확인할 수 있다. 추가로 매개변수로 정수가 전달된 경우와 문자열이 전달된 경우 모두 finally 부분은 실행되는 것을 확인할 수 있다. 따라서 return 키워드를 만나더라도 finally 부분은 반드시 실행된다는 것을 알 수 있다.

 

2-2) try 구문 내부 break, continue

def fun():
    for i in range(10):
        try:
            if i == 3:
                continue
            if i == 5:
                break
        except:
            print("Run Except")
        else:
            print(i)
        finally:
            print("fun 함수 종료")

fun()

    위 코드는 for 반복문 내부의 try 구문이 사용되었다. i가 3인 경우에는 건너뛰고(continue) i가 5인 경우에는 실행이 종료(break)된다. 출력 결과를 확인해보면 finally 부분의 코드는 continue, break가 된 경우에도 실행이 된다는 것을 확인할 수 있다.

 

3) 예외 종류별 처리

  예외가 발생하는 원인은 정말 다양하고 또 그만큼 당연히 예외의 종류도 다양하다. 파이썬에서는 발생한 예외를 종류별로 처리하는 것이 가능하다.

input_value = input()

# try~except 구문을 사용한 예외 처리
try:
    print(int(input_value))
except Exception as exception:
    print("Not Integer Type Value")
    print(type(exception))
    print(exception)

  위 코드는 try 구문을 사용하여 예외를 처리하고 있고 except 구문에서는 모든 예외(Exception)에 대한 처리를 하고 있다. 발생한 예외는 이를 저장할 변수(위 코드에서는 exception)에 저장하여 type과 내용을 출력할 수 있다. 위 코드에서 발생한 예외의 타입은 ValueError이므로 코드를 아래와 같이 수정할 수 있다.

input_value = input()

# try~except 구문을 사용한 예외 처리
try:
    print(int(input_value))
except ValueError as exception:
    print("Not Integer Type Value")
    print(type(exception))
    print(exception)

  이번에는 리스트의 인덱스 범위를 초과한 접근을 시도했을 때 발생하는 예외를 처리해보자. 이때 발생하는 예외의 종류는 IndexError이므로 이에 맞게 수정해주면 된다.

value_list = [1, 2, 3, 4, 5]

# try~except 구문을 사용한 예외 처리
try:
    print(value_list[5])
except IndexError as exception:
    print("IndexError")
    print(type(exception))
    print(exception)

  이로써 발생할 예외를 종류별로 처리할 수 있다는 것을 확인하였다. 그러면 이번에는 except 구문을 여러개 사용하여 하나의 코드에서 발생할 수 있는 예외를 종류별로 처리해보자.

value_list = [1, 2, 3, 4, 5]

# try~except 구문을 사용한 예외 처리
try:
    n = int(input("> "))
    print(value_list[n])
except IndexError as exception:
    print("IndexError")
    print(type(exception))
    print(exception)
except ValueError as exception:
    print("ValueError")
    print(type(exception))
    print(exception)

<정수가 아닌 데이터 입력>
<리스트 범위 초과 정수 입력>

  이처럼 except 구문을 여러개 사용하면 발생할 오류를 종류별로 처리할 수 있게 되므로 어느 상황에서 어떤 예외가 발생하는지 확인이 필요한 경우 등에 맞게 사용하면 예외를 처리하기 수월해진다.