[파이썬] 예외 처리 방식과 스택 추적 구현 방법

프로그램에서 오류가 발생했을 때 도움이 되는 스택 트레이스. Python이란 언어의 오류 처리 방법과 거기에 스택 트레이스 정보를 얻어 분석하는 방법 소개합니다.



스택 추적

스택 추적(Stack trace 보는 법)은 프로그램에서 예외가 발생했을 때 어떻게 함수가 호출되었는지, 어디에서 오류가 발생했는지를 특정할 수 있는 수단(방법)입니다. 문제 발생 시 원인 규명에 도움이 됩니다.


예를 들어 다음과 같은 파이썬 프로그램이 있습니다.


1
2
3
4
5
6
7
8
9
10
11
def a () : "" "b 함수를 호출" "" 
    b ()
 
def b () : "" "c 함수를 호출" "" 
    c ()
 
def c () : "" "예외가 발생한다" "" char = None char . format ( 'hello' ) # 여기서 예외 발생
 
 
# a 함수에서 호출
a ()
cs


여기선 a() -> b() -> c()로 호출되며 c()에서 예외가 발생합니다.


이 코드를 실행하면 다음의 스택 추적 내용이 표시됩니다.


1
2
3
4
5
6
7
8
9
10
11
12
$ python3 sample.py 
 
Traceback (most recent call last):
  File "sample.py", line 14in <module>
    a()
  File "ssample.py", line 5in a
    b()
  File "ssample.py", line 8in b
    c()
  File "ssample.py", line 12in c
    char.format('hello')
AttributeError: 'NoneType' object has no attribute 'format'
cs


영어가 많다고 멈칫하지 않고 잘 읽어보면, sample.py 12번째 줄(line 12)에서 c() 함수(in c)에 있는 char.format('hello')에서 오류가 발생했습니다. 오류 내용은 'NoneType' object has no attribute 'foramt'임을 알 수 있습니다.


위 프로그램에서 try~except를 이용한 오류 처리를 하지 않았습니다. 그러므로 파이썬 실행 환경이 자동으로 위의 스택 트레이스를 표시한 다음 프로그램은 오류를 출력하고 종료됩니다. 다만, 실제로 사용하는 프로그램에서는 마음대로 프로그램이 종료되면 곤란합니다. 예를 들어 웹 응용 프로그램의 경우 사용자 친화적인 오류 메시지를 사용자에게 보여줘야 합니다. 이 경우에는 위의 코드가 아니라 오류 처리가 필요합니다.

예외 처리를 할 때도 스택 트레이스 정보를 얻어 오류의 원인 규명까지 할 수 있다는 뜻입니다.


예외 처리 (try / except) 추가

위의 프로그램에 예외 처리를 추가합시다. try 그리고 except를 추가합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def a():
    b()
 
def b():
    c()
 
def c():
    char = None
    char.format('hello')
 
# 예외 처리 추가
try:
    a()
except Exception as e:
    # Exception 정보를 얻어 내용을 표시한다
    print(e)
cs


예외 처리 루틴이 동작하므로 이번 프로그램은 종료되지 않습니다. 예외 처리 시 print(e) 표시하고 오류 내용을 표시해 봤습니다.


1
2
3
$ python3 sample.py 
 
'NoneType' object has no attribute 'format' # print(e) 내용
cs


실행해 보시면 아시겠지만, 오류 내용이 한 줄로 축약된 것을 알 수 있습니다. 오류 원인은 알 수 있지만, 오류가 어디에서 발생했는지는 알 수 없습니다. 이런 작은 프로그램이면 오류 부분을 파악할 수 있으나, 큰 프로그램이면 어디서 발생한 에러인지 전혀 짐작 가지 않을 겁니다. 그래서 스택 트레이스 정보를 취득해야 합니다.


예외 처리 시에 스택 트레이스 취득하기

스택 트레이스를 취득하기 위해 traceback 모듈을 추가로 import 합니다. traceback.foramt_exc()를 사용하여 스택 추적 정보를 얻을 수 있습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import traceback
 
def a():
    b()
 
def b():
    c()
 
def c():
    char = None
    char.format('hello')
 
try:
    a()
except Exception as e:
    print(traceback.format_exc())
cs


실행하면 다음과 같이 표시됩니다.


1
2
3
4
5
6
7
8
9
10
11
12
$ python3 sample.py 
 
Traceback (most recent call last):
  File "sample.py", line 15in <module>
    a()
  File "sample.py", line 5in a
    b()
  File "sample.py", line 8in b
    c()
  File "sample.py", line 12in c
    char.format('hello')
AttributeError: 'NoneType' object has no attribute 'format'
cs


처음에 봤었던 스택 추적 결과와 같은 내용을 볼 수 있습니다. 처음과 다른 점은 이번에는 print() 함수를 사용하여 스택 추적 결과의 출력을 제어한다는 것입니다. 직접 컨트롤 할 수 있으므로, 예를 들면 파이썬 logger 패키지를 사용하여 기록할 수 있습니다.


실무에선 당연히 이런 부분을 적용해야 합니다.

참고 : 스택 추적을 조금 더 꼼꼼하게

위의 구현에는 문제가 없습니다만, 조금 신경 쓰이는 부분이 있어 꼼꼼하게 더 살펴봤습니다.

traceback.format_exc()에서 획득한 정보로 스택 추적 및 에러 원인을 취득했습니다. 여기에 더해 sys.exc_info()를 개별적으로 호출할 수 있습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
import sys
import traceback
 
# ..생략.. # 
 
try:
    a()
except Exception as e:
    # 개별적으로 데이터 출력
    type_, value, traceback_ = sys.exc_info()
    print(type_)
    print(value)
    print(traceback_)
cs


다음은 실행 결과입니다.


1
2
3
4
5
6
7
8
9
10
$ python3 sample.py 
 
# print(type_)
<class 'AttributeError'>
 
# print(value)
'NoneType' object has no attribute 'format'
 
# print(traceback_)
<traceback object at 0x7f8f6002c188>
cs


다만, 이런 포맷으로 내용 파악하기 어렵다면(내 스타일 아니라면), traceback.format_exception()을 사용하여 문장을 꾸밀 수 있습니다.


1
print(traceback.format_exception(type_, value, traceback_))
cs


1
2
3
4
# 실행 결과
$ python3 sample.py 
 
['Traceback (most recent call last):\n''  File "sample.py", line 15, in <module>\n    a()\n''  File "sample.py", line 5, in a\n    b()\n''  File "sample.py", line 8, in b\n    c()\n''  File "sample.py", line 12, in c\n    char.format(\'hello\')\n'"AttributeError: 'NoneType' object has no attribute 'format'\n"]
cs


이렇게 스택 추적 결과를 한 줄씩 배열에서 얻을 수 있습니다.

어떻게 사용하건 정보 취득은 됩니다. 그래도 저는 traceback.format_exc()를 사용하는 것이 편하네요. 사용자 정의 예외 처리 메시지는 회사, 개인에 따라 다르게 구현하면 됩니다.


마지막으로

오늘은 Python 예외 처리 방법 및 스택 추적 방법(Stack trace 보는 법)에 대해 포스팅했습니다. 예외 처리는 프로덕션 환경에서 문제가 일어났을 때, 사용자에게 연락을 받았을 때 그 원인을 규명하기 위해 매우 중요합니다. 원인 파악에 시간이 걸렸다고 생각될 땐 스택 트레이스를 출력하는 소스 코드를 추가로 적용하는 것이 좋을지도 모릅니다.


끝까지 봐주셔서 감사합니다!




파이썬 입문 강좌 11강


관련 글

SQLite3 자료형 정리

https://codingcoding.tistory.com/340


파이썬 컴프리헨션 예제 8개

https://codingcoding.tistory.com/1036


[파이썬 리스트] 정수를 모두 제곱하여 출력하기

https://codingcoding.tistory.com/1124


파이썬 gui, tkinter Class 활용한 입력창 구현

https://codingcoding.tistory.com/1045

댓글(0)

Designed by JB FACTORY