본문 바로가기
코드/python

파이썬 예외 처리 관련

by WeZZ 2012. 1. 8.

3) 예외처리

예외 처리(try, except)

프로그램을 만들다 보면 수없이 많은 에러가 난다. 물론 에러가 나는 이유는 프로그램이 오동작을 하지 않기 하기 위한 파이썬의 배려이다. 하지만 때때로 이러한 에러를 무시하고 싶을 때도 있고, 에러가 날 때 그에 맞는 적절한 처리를 하고 싶을 때가 생기게 된다. 이에 파이썬에는 try, except를 이용해서 에러를 처리할 수 있게 해준다. 에러 처리하는 방법에 대해서 알게 되면 매우 유연한 프로그래밍을 구사 할 수 있을 것이다.


에러는 어떤 때 일어나는가?

에러를 처리하는 방법을 알기 전에 어떤 상황에서 에러가 나는지 한번 보자. 오타를 쳤을 때 나는 구문 에러 같은 것이 아닌 실제 프로그램에서 잘 발생하는 에러를 보기로 하자. 먼저 없는 파일을 열려고 시도해 보자.

>>> f = open('나없는파일', 'r') 
Traceback (most recent call last): 
File "", line 1, in ? 

IOError: [Errno 2] No such file or directory: '\xb3\xaa\xbe\xf8\xb4\xc2\xc6\xc4\xc0\xcf'

위의 예에서 보듯이 없는 파일을 열려고 시도하면 IOError라는 이름의 에러가 발생하게 된다. 위의 예에서 '나없는파일'이 한글이기 때문에 다음처럼 깨져 보이는 것이다. 이것은 신경쓰지 말도록 하자.

'\xb3\xaa\xbe\xf8\xb4\xc2\xc6\xc4\xc0\xcf'


이번에는 또 하나 자주 발생하는 에러로 0으로 어떤 다른 숫자를 나누는 경우를 생각해 보자.

>>> 4 / 0 
Traceback (most recent call last): 
File "", line 1, in ? 
ZeroDivisionError: integer division or modulo by zero 
>>>

4를 0으로 나누려니까 ZeroDivisionError라는 이름의 에러가 발생한다.


마지막으로 한가지 에러만 더 들어 보자. 다음의 에러는 정말 빈번하게 일어난다.

>>> a = [1,2,3] 
>>> a[4] 
Traceback (most recent call last): 
File "", line 1, in ? 
IndexError: list index out of range 
>>>

a는 [1, 2, 3]이란 리스트인데 a[4]는 a 리스트에서 구할 수 없는 값이기 때문에 IndexError가 나게 된다. 파이썬은 이런 에러가 나면 프로그램을 중단하고 에러메시지를 보여준다.


에러 처리하기

자, 이제 유연한 프로그래밍을 위한 에러처리의 기법에 대해서 살펴보자. 다음은 에러 처리를 위한 try, except문의 기본 구조이다.

 
try: 
    ...
except [발생에러[, 에러메시지변수]]:
    ...

try문안의 수행할 문장들이 에러가 나지 않는다면 except문 다음의 문장들은 수행이 되지 않는다. 하지만 try문안의 문장들을 수행 중 에러가 발생하면 except문을 수행한다.


except문을 자세히 보자.

except [발생에러 [, 에러메시지변수]]:


위에서 보면 [발생에러 [, 에러메시지변수]]는 생략이 가능하다는 전형적인 표기법이다. 즉 다음처럼 try, except만 써도 되고


첫 번째

try:
    ...
 except:
    ...


다음과 같이 발생에러만 포함한 except문을 써도 되고

두 번째

try
    ...
except 발생에러:
    ...


다음과 같이 발생에러와 에러메시지변수까지 포함한 except문을 써도 된다.

세 번째

try
    ...
except 발생에러, 에러메시지변수:
    ...

이중에서 한가지를 택해서 쓰게 되는데 첫 번째의 경우는 에러 종류에 상관없이 에러가 발생하기만 하면 except문 다음의 문장들을 수행한다는 말이고 두 번째 경우는 에러가 발생했을 때 except문에 미리 정해놓은 에러이름과 일치할 때만 except문 다음의 문장을 수행한다는 말이고 세 번째의 경우는 두 번째의 경우에다가 에러메시지를 담은 변수하나를 더 생성하게 하는 방법이다.


세 번째 방법의 예를 잠시 들어 보면 다음과 같다.

try: 
    4 / 0 
except ZeroDivisionError, e: 
    print e

위처럼 4를 0으로 나누려고 하면 ZeroDivisioError가 발생하기 때문에 except문이 실행되고 위의 except문은 e라는 에러메시지를 담은 변수를 출력 시키기 때문에 결과값은 다음과 같을 것이다.

결과값: integer division or modulo by zero


에러처리하기 예제

자 이제 실제적인 에러 처리의 예를 들어보기로 하자. 어떤 프로그램을 만들었는데 만약 파일이 존재하면 읽기 모드로 열고 존재하지 않으면 쓰기 모드로 파일을 여는 프로그램을 만든다고 가정해 보자. 독자라면 어떻게 하겠는가?


필자는 다음과 같은 방식을 택할 것이다.

>>> try: 
. . .     f = open("나없는파일.txt", 'r') 
. . . except IOError: 
. . .     print "쓰기모드로 파일을 엽니다." 
. . .     f = open("나없는파일.txt", 'w') 
. . . 
쓰기모드로 파일을 엽니다.

위와 같이 하였을 때 try문을 우선 실행하게 되는데 try문의 f = open("나없는파일.txt“, 'r')처럼 없는 파일을 읽기 모드로 열려고 하면 IOError가 나게 된다. 바로 이 에러가 나는 순간에 except문의 에러이름과 똑같은지를 판단하게 된다. 만약 에러이름이 except문에서 정해놓은 에러이름과 일치할 때 except문 다음의 문장들을 수행하게 된다. 즉, 위의 예에서 보면 "쓰기모드로 파일을 엽니다”라는 문자열을 출력하고 “나없는파일.txt”라는 파일을 쓰기 모드로 열게 되는 것이다.

실제로 프로그램을 만들어 보면 위처럼 미리 에러를 예측하기가 쉽지 않다. 대부분의 에러처리는 실제 프로그램을 작성하고 실행될 때 발생하는 에러를 조사한 다음에 try, except를 이용해서 에러를 처리하게 된다.


에러 발생시키기(raise)

좀 이상하긴 하지만 에러를 일부러 발생시켜야 할 경우도 생기게 된다. 파이썬은 raise라는 명령어를 이용하여 에러를 강제로 발생시킨다. 예를 들어 Bird라는 클래스를 상속받는 자식 클래스는 반드시 fly라는 함수를 구현하게 만들고 싶은 경우(강제로 그렇게 하고 싶은경우)가 있을 수 있다.

class Bird:
    def fly(self):
        raise NotImplementedError

만약 위 Bird클래스를 상속받는 자식 클래스가 fly라는 함수를 구현하지 않은 상태에서 fly함수가 호출되면 반드시 위 에러가 발생하게 될 것이다.


Bird클래스의 fly함수를 구현한 자식클래스를 보자.

class Eagle(Bird):
    def fly(self):
        return "very fast"



출처 : http://codejob.co.kr/docs/page/58/



참고 : except 발생에러, 에러메시지변수: 파이썬 3.0에서는 다음과 같이 해야 합니다. except 발생에러 as 에러메시지변수: