본문 바로가기
Study/Python

[Python] 예외(exception)와 예외처리(exception handling)

by ngool 2024. 8. 8.

이번 포스팅은 파이썬에서 발생할 수 있는 예외의 종류와, 이러한 예외들을 처리할 수 있는 예외처리 기법에 대해 공부한 내용을 정리한 것입니다.

 

예외처리는 코드에서 에러가 발생했을 때 어떠한 액션을 취하게 만들기 위한 기술로, 다양한 상황에서 유용하게 사용될 수 있습니다.


예외 (Exception)

프로그래밍에서 예외는 "프로그램 실행 중에 감지되는 에러"를 의미합니다.

파이썬에 내장되어 있는 예외 상황은 다음과 같습니다.

 

  • ZeroDivisionError: 나누기 또는 모듈로 연산의 두 번째 인자가 0일 때 발생
10/0 # ZeroDivisionErorr: division by zero

 

  • NameError: 지역 또는 전역 이름을 찾을 수 없을 때 발생
print(name_error)
# NameError: name 'name_erorr' is not defined

 

  • TypeError: 어떠한 액션을 취했을 때 그 액션에 알맞는 데이터 타입이 오지 않았을 경우, 또는 함수를 호출할 때 인자의 개수가 초과될 경우 발생
# 타입 불일치
'2' + 2 # TypeError: can only concatenate str (not "int") to str

# 인자 누락
sum()  # TypeError: sum() takes at least 1 positional argument (0 given)
 
# 인자 초과
sum(1, 2, 3)  # TypeError: sum() takes at most 2 arguments (3 given)

# 인자 타입 불일치
import random
random.sample(1, 2)
# TypeError: Population must be a sequence. For dicts or sets, use sorted(d).

 

  • ValueError: 연산이나 함수에 문제가 없지만 부적절한 값을 가진 인자를 받았고, 상황이 IndexError 처럼 더 구체적인 예외로 설명되지 않는 경우 발생
int('1.5')  # ValueError: invalid literal for int() with base 10: '3.5'

range(3).index(6)  # ValueError: 6 is not in range

 

  • IndexError: 시퀀스 인덱스가 범위를 벗어날 때 발생
empty_list = []
empty_list[2]
# IndexError: list index out of range

 

  • KeyError: 딕셔너리에 해당 키가 존재하지 않는 경우
person = {'name': 'Alice'}
person['age']  # KeyError: 'age'

 

  • ModuleNotFoundError: 모듈을 찾을 수 없을 때 발생
import hahaha  # ModuleNotFoundError: No module named 'hahaha'

 

  • ImportError: import 하려는 이름을 찾을 수 없을 때 발생
from random import hahaha
# ImportError: cannot import name 'hahaha' from 'random'

 

  • KeyboardInterrupt: 사용자가 Control-C 또는 Delete를 누를 때 발생 (무한루프 시 강제 종료)
while True:
	continue

'''
Traceback (most recent call last):
	File "...", line 2, in <module>
		continue
KeyboardInterrupt
'''

 

  • IndentationError: 잘못된 들여쓰기와 관련된 문법 오류
for i in range(10):
print(i)  # IndentationError: expected an indented block

 

위 에러들은 파이썬을 자주 사용하시는 분들이라면 많이 보셨을 것입니다.

저도 굉장히 익숙한데요...ㅎㅎ

어떤 에러가 어떤 상황에 나는지 잘 알고 있다면, 에러가 발생했을 때 더 빠르게 대처할 수 있을 것입니다!


예외처리

파이썬에서 예외처리는 다음 4가지 구문을 사용합니다.

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

try, except만 빨간 글씨로 했을까요?

 

이 두 가지가 예외처리의 핵심이기 때문입니다!

다른건 없어도 되지만, try, except이 없다면 그것은 진정한 예외처리라고 볼 수 없죠.

 

자 그럼 본격적으로 코드에서 어떤식으로 이 4가지 구문을 사용하는지 확인해보겠습니다.

try:
    x = int(input('숫자를 입력하세요: '))
    y = 10 / x
except ZeroDivisionError:
    print('0으로 나눌 수 없습니다.')
except ValueError:
    print('유효한 숫자가 아닙니다.')
else:
    print(f'결과: {y}')
finally:
    print('프로그램이 종료되었습니다.')

 

위 코드를 해석하면 이렇습니다.

  1. try : x라는 숫자를 입력 받고, 10을 x로 나눈 값을 y에 할당하는 행동을 시도합니다.
  2. except ZeroDivisionError : x가 0이었을 경우 10을 0으로 나눌 수 없기 때문에 ZeroDivisionError가 발생하여 해당 구문이 실행됩니다.
  3. except ValueError : input()으로 입력 받는 값이 숫자가 아닐 경우 int() 함수 호출 시 ValueError가 발생하여 해당 구문이 실행됩니다.
  4. else : 어떠한 에러도 발생하지 않으면, except 구문으로 들어가지 않고 곧바로 else 구문이 실행됩니다.
  5. finally : 에러가 발생하여 except 구문이 실행되었든, 에러가 발생하지 않아 else 구문이 실행되었든, 관계 없이 마지막에는 무조건 finally 구문이 실행됩니다.
except을 굳이 저렇게 두 번 써야하나요?

 

# 이렇게도 가능
try:
    num = int(input('100으로 나눌 값을 입력하시오 : '))
    print(100 / num)
except (ValueError, ZeroDivisionError):
    print('제대로 입력해주세요.')

 

아뇨~~ 이렇게 묶어서 써도 되네요 ㅎㅎ

 

except 구문을 사용할 때 꼭 저렇게 에러 이름을 명시해줘야 하나요?
# 이렇게도 가능
try:
    num = int(input('100으로 나눌 값을 입력하시오 : '))
    print(100 / num)
except:
    print('제대로 입력해주세요.')

 

역시 아닙니다~~ 이렇게 생략해도 됩니다!

 

그.러.나!!

이렇게 작성하게 되면 ValueError, ZeroDivisionError 외에 다른 에러가 발생하더라도 except 구문이 실행되어 버립니다.

그래도 상관없다면 이렇게 생략해도 되지만..

 

이왕이면 확실하게 적어주는게 가독성 면에서 좋겠죠?

 

지금까지 예외와 예외처리를 알아보았습니다.
예외의 종류와 예외처리 기술을 알고 있다면 코드 디버깅할 때 유용하게 사용할 수 있겠네요!!