
Python 예외 처리
오류가 발생하는 상황
오류를 처리하는 방법을 공부하기 전에 어떤 상황에서 오류가 발생하는지 한번 알아보자.
오타를 입력했을 때 발생하는 구문 오류 같은 것이 아닌 실제 프로그램에서 자주 발생하는 오류를 중심으로 살펴보자.
먼저 존재하지 않는 파일을 사용하려고 시도했을 때 발생하는 오류이다.
아래 예제에서 볼 수 있듯이 없는 파일을 열려고 시도하면 FileNotFoundError 오류가 발생한다.
## 존재하지 않은 파일 열기
f = open("없는파일", 'r')
→ Traceback (most recent call last):
File "<python-input-0>", line 1, in <module>
FileNotFoundError: [Errno 2] No such file or directory: '없는파일'
이번에는 0으로 다른 숫자를 나누는 경우를 생각해 보자. 이 역시 자주 발생하는 오류이다.
4를 0으로 나누려니까 ZeroDivisionError 오류가 발생한다.
## 숫자 0으로 나누기
4/0
→ Traceback (most recent call last):
File "<python-input-1>", line 1, in <module>
ZeroDivisionError: division by zero
마지막으로 한 가지 예를 더 살펴보자.
a[3]은 a의 네 번째 요솟값을 가리키는데, a 리스트에는 값이 3개밖에 없으므로([1, 2, 3]) 값을 얻을 수 없다.
따라서 IndexError 오류가 발생한다. 파이썬은 이런 오류가 발생하면 프로그램을 중단하고 오류 메시지를 보여 준다.
## 숫자 0으로 나누기
a = [1, 2, 3]
a[3]
→ Traceback (most recent call last):
File "<python-input-3>", line 1, in <module>
IndexError: list index out of range
오류 예외 처리 기법
○ try, except문
다음은 오류를 처리하기 위한 try,except 문의 기본 구조이다. try 블록 수행 중 오류가 발생하면 except 블록이 수행된다.
하지만 try블록에서 오류가 발생하지 않는다면 except블록은 수행되지 않는다.
## try,except문 기본 구조
try:
...
except [발생오류 [as 오류변수]]:
...
except 구문을 자세히 살펴보자. 'except [발생오류 [as 오류변수]]:'를 보면 [ ] 기호를 사용하는데
이 기호는 괄호 안의 내용을 생략할 수 있다는 관례 표기법이다. 즉 except 구문은 다음 3가지 방법으로 사용할 수 있다.
1. try,except만 쓰는 방법
## try,except만 쓰는 방법
try:
...
except:
...
이 경우 오류의 종류에 상관없이 오류가 발생하면 except 블록을 수행한다.
2. 발생 오류만 포함한 except문
이 경우 오류가 발생했을 때, except 문에 미리 정해 놓은 오류와 동일한 오류일 경우에만 except 블록을 수행한다는 뜻이다.
## 발생 오류만 포함한 except문
try:
...
except 발생 오류:
...
3. 발생 오류와 오류 변수까지 포함한 except 문
이 경우는 두 번째 경우에서 오류 메시지의 내용까지 알고 싶을 때 사용하는 방법이다.
## 발생 오류와 오류 변수까지 포함한 except 문
try:
...
except 발생 오류 as 오류 메시지 변수:
...
다음 예제를 통해 이 방법을 이해해 보자.
## 발생 오류와 오류 변수까지 포함한 except 문 예제
try:
4/0
except ZeroDivisionError as e:
print(e)
→ division by zero
위 예제처럼 4를 0으로 나누려고 하면 ZeroDivisionError가 발생하여 except 블록이 실행되고
오류 변수 e에 담기는 오류 메시지를 출력할 수 있다. 출력되는 오류 메시지는 다음과 같다.
○ try...finally
try 문에는 finally 절을 사용할 수 있다. finally 절은 try 문 수행 도중 예외 발생 여부에 상관없이 항상 수행된다.
보통 finally 절은 사용한 리소스를 close해야 할 때 많이 사용한다. 다음 예제를 살펴보자.
파일을 쓰기 모드로 연 후에 try문을 수행한 후 예외 발생 여부와 상관없이 finally절에서 f.close()로 열린 파일을 닫을 수 있다.
## try...finally 예제
try:
f = open('ipmes.txt','w')
# 무언가를 수행한다.
finally:
f.close()
여러 개의 오류 처리하기
try 문 안에서 여러 개의 오류를 처리하려면 다음과 같이 사용해야 한다.
## 여러 개의 오류처리
try:
...
except 발생오류1:
...
except 발생오류2:
...
아래 예제는 0으로 나누는 오류와 인덱싱 오류를 다음과 같이 처리할 수 있다.
## 여러 개의 오류처리 예제1
try:
a = [1,2]
print(a[3])
4/0
except ZeroDivisionError:
print("0으로 나눌 수 없습니다.")
except IndexError:
print("인덱싱 할 수 없습니다.")
→ 인덱싱 할 수 없습니다.
a는 2개의 요솟값을 가지고 있으므로 a[3]이 IndexError를 발생시켜 "인덱싱할 수 없습니다."라는 문자열을 출력할 것이다.
인덱싱 오류가 먼저 발생했으므로 '4/0'에 따른 ZeroDivisionError 오류는 발생하지 않는다.
앞에서 알아본 것과 마찬가지로 오류 메시지도 다음과 같이 가져올 수 있다.
## 여러 개의 오류처리 예제2
try:
a = [1,2]
print(a[3])
4/0
except ZeroDivisionError as e:
print(e)
except IndexError as e:
print(e)
→ list index out of range
다음과 같이 ZeroDivisionError와 IndexError를 함께 처리할 수도 있다.
2개 이상의 오류를 함께 처리하기 위해서는 위와 같이 괄호를 사용하여 함께 묶어 처리하면 된다.
## 여러 개의 오류처리 예제3
try:
a = [1,2]
print(a[3])
4/0
except (ZeroDivisionError, IndexError) as e:
print(e)
→ list index out of range
try-else 문
Python 예외 처리
try 문에는 다음처럼 else 절을 사용할 수도 있다.
try 문 수행 중 오류가 발생하면 except 절, 오류가 발생하지 않으면 else 절이 수행된다.
## try-else문 구조
try:
...
except [발생오류 [as 오류변수]]:
...
else: # 오류가 없을 경우에만 수행
...
다음은 try 문에 else 절을 사용한 간단한 예제이다.
만약 '나이를 입력하세요: '라는 질문에 숫자가 아닌 다른 값을 입력하면 오류가 발생하여
'입력이 정확하지 않습니다.'라는 문장을 출력한다. 오류가 없을 경우에만 else 절이 수행된다.
## try-else문 예제
try:
age=int(input('나이를 입력하세요: '))
except:
print('입력이 정확하지 않습니다.')
else:
if age <= 18:
print('미성년자는 출입금지입니다.')
else:
print('환영합니다.')
나이를 입력하세요: 한 살
→ 입력이 정확하지 않습니다.
나이를 입력하세요: 15
→ 미성년자는 출입금지입니다.
나이를 입력하세요: 21
→ 환영합니다.
오류 회피하기
프로그래밍을 하다 보면 특정 오류가 발생할 경우 그냥 통과시켜야 할 때가 있다. 다음 예를 살펴 보자.
try 문 안에서 FileNotFoundError가 발생할 경우, pass를 사용하여 오류를 그냥 회피하도록 작성한 예제이다.
## 오류 회피하기 예제
try:
f = open("없는파일", 'r')
except FileNotFoundError:
pass
...
오류 일부러 발생시키기
이상하게 들리겠지만, 프로그래밍을 하다 보면 종종 오류를 일부러 발생시켜야 할 경우도 생긴다.
파이썬은 raise 명령어를 사용해 오류를 강제로 발생시킬 수 있다.
예를 들어 Bird 클래스를 상속받는 자식 클래스는 반드시 fly라는 함수를 구현하도록 만들고 싶은 경우가 있을 수 있다.
다음 예제를 살펴보자.
## raise 명령어 사용 예제
class Bird:
def fly(self):
raise NotImplementedError
위 예제는 Bird 클래스를 상속받는 자식 클래스는 반드시 fly 함수를 구현해야 한다는 의지를 보여 준다.
만약 하위 클래스가 fly 함수를 구현하지 않은 상태로 fly 함수를 호출한다면 어떻게 될까?
## raise 명령어 사용 예제
class Eagle(Bird):
pass
eagle = Eagle()
eagle.fly()
→ Traceback (most recent call last):
File "c:\ipmes1\error_raise.py", line 9, in <module>
File "c:\ipmes1\error_raise.py", line 4, in fly
raise NotImplementedError
NotImplementedError
Eagle 클래스는 Bird 클래스를 상속받았다. 그런데 Eagle 클래스는 fly 메서드를 오버라이딩하여 구현하지 않았다.
따라서 eagle 객체의 fly 메서드를 수행하는 순간 Bird 클래스의 fly 메서드가 수행되어 NotImplementedError가 발생한다.
※ 상속받는 클래스에서 함수를 재구현하는 것을 메서드 오버라이딩이라고 부른다.
NotImplementedError가 발생하지 않게 하려면 다음과 같이 Eagle 클래스에 fly 함수를 구현해야 한다.
아래 예제처럼 fly 함수를 구현한 후 프로그램을 실행하면 오류 없이 'very fast' 문장을 출력한다.
## fly 함수 구현
class Eagle(Bird):
def fly(self):
print("very fast")
eagle = Eagle()
eagle.fly()
→ very fast
예외 만들기
프로그램을 수행하다가 특수한 경우에만 예외 처리를 하려고 종종 예외를 만들어서 사용한다.
이번에는 직접 예외를 만들어 보자. 예외는 다음과 같이 파이썬 내장 클래스인 Exception 클래스를 상속하여 만들 수 있다.
그 다음, 별명을 출력해 주는 함수를 다음과 같이 작성한다.
이후, say_jack 함수를 호출해 보자.
## 예외 만들기
class MyError(Exception):
pass
def say_jack(jack):
if jack == '바보':
raise MyError()
print(jack)
say_jack("천사")
→ 천사
say_jack("바보")
File "c:\ipmes1\예외 만들기.py", line 9, in <module>
say_jack("바보")
File "c:\ipmes1\예외 만들기.py", line 6, in say_jack
raise MyError()
MyError
이번에는 예외 처리 기법을 사용하여 MyError 발생을 예외 처리해 보자.
## 예외 처리 기법 사용 에러 발생 처리
class MyError(Exception):
pass
def say_jack(jack):
if jack == '바보':
raise MyError()
print(jack)
try:
say_jack("천사")
say_jack("바보")
except MyError:
print("허용되지 않은 별명입니다.")
→ 천사
→ 허용되지 않은 별명입니다.
만약 오류 메시지를 사용하고 싶다면 다음처럼 예외 처리를 하면 된다.
## 예외 처리 기법 사용 오류 메시지 사용
try:
say_jack("천사")
say_jack("바보")
except MyError as e:
print(e)
→ 천사
→ "" #빈칸
하지만 위와 같이 프로그램을 실행하면 print(e)로 오류 메시지가 출력되지 않는 것을 확인할 수 있다.
오류 메시지를 출력했을 때 오류 메시지가 보이게 하려면 오류 클래스에 다음과 같은 __str__ 메서드를 구현해야 한다.
__str__메서드는 print(e)처럼 오류 메시지를 print문으로 출력할 경우에 호출되는 메서드이다.
## __str__ 메서드 사용
class MyError(Exception):
def __str__(self):
return "허용되지 않는 별명입니다."
def say_jack(jack):
if jack == '바보':
raise MyError()
print(jack)
try:
say_jack("천사")
say_jack("바보")
except MyError as e:
print(e)
→ 천사
→ 허용되지 않는 별명입니다.
이번 연구 노트는 파이썬의 예외 처리에 대하여 작성하였다.
빈번하게 발생하는 오류의 종류도 알 수 있었고, 오류를 처리하는 방법에 대하여 알아보았다.
다음 연구 주제는 파이썬 내장 함수에 대하여 알아보겠다.

TEL (062-226-1777, 010-9891-7244), E-mail (ipmes@ipmes.co.kr)
임베디드 시스템 | PCB 설계 제작 | 펌웨어 개발 | 신호처리 | 응용프로그램