def func1(a, b):
return a / b
def func2(x):
a = x
b = x - 1
return func1(a, b)오류와 디버깅
코드 개발과 데이터 분석 과정에는 언제나 시행착오가 따르기 마련입니다. IPython은 이러한 과정을 더 효율적으로 만들어주는 다양한 도구들을 갖추고 있습니다. 이번 섹션에서는 파이썬의 예외 보고 방식을 제어하는 옵션들을 살펴보고, 코드 오류를 해결하기 위한 디버깅 도구들을 알아보겠습니다.
예외 보고 제어: %xmode
파이썬 스크립트 실행이 실패하면 예외(Exception)가 발생합니다. 인터프리터가 예외를 만나면 오류 원인에 대한 정보인 트레이스백(Traceback)을 출력합니다. IPython의 %xmode 매직 명령어를 사용하면 예외 발생 시 출력되는 정보의 양을 조절합니다. 다음 코드를 예로 들어보겠습니다.
func2(1)--------------------------------------------------------------------------- ZeroDivisionError Traceback (most recent call last) <ipython-input-2-b2e110f6fc8f> in <module>() ----> 1 func2(1) <ipython-input-1-d849e34d61fb> in func2(x) 5 a = x 6 b = x - 1 ----> 7 return func1(a, b) <ipython-input-1-d849e34d61fb> in func1(a, b) 1 def func1(a, b): ----> 2 return a / b 3 4 def func2(x): 5 a = x ZeroDivisionError: division by zero
func2를 호출하면 오류가 발생하며, 출력된 트레이스백을 통해 정확히 어떤 일이 일어났는지 확인합니다. 기본 모드에서 트레이스백은 오류를 일으킨 각 단계의 맥락을 보여주는 여러 줄의 정보를 담고 있습니다. %xmode 매직 명령어(Exception mode의 약자)를 사용하면 이 정보를 원하는 대로 바꿀 수 있습니다.
%xmode는 모드 이름을 인자로 받으며, Plain, Context, Verbose 세 가지 옵션이 있습니다. 기본값은 방금 본 것과 같은 결과를 보여주는 Context입니다. Plain 모드는 훨씬 간결하게 핵심 정보만 보여줍니다.
%xmode PlainException reporting mode: Plain
func2(1)Traceback (most recent call last): File "<ipython-input-4-b2e110f6fc8f>", line 1, in <module> func2(1) File "<ipython-input-1-d849e34d61fb>", line 7, in func2 return func1(a, b) File "<ipython-input-1-d849e34d61fb>", line 2, in func1 return a / b ZeroDivisionError: division by zero
Verbose 모드는 호출된 함수의 인자값까지 포함하여 더 상세한 정보를 추가해 줍니다.
%xmode VerboseException reporting mode: Verbose
func2(1)--------------------------------------------------------------------------- ZeroDivisionError Traceback (most recent call last) <ipython-input-6-b2e110f6fc8f> in <module>() ----> 1 func2(1) global func2 = <function func2 at 0x103729320> <ipython-input-1-d849e34d61fb> in func2(x=1) 5 a = x 6 b = x - 1 ----> 7 return func1(a, b) global func1 = <function func1 at 0x1037294d0> a = 1 b = 0 <ipython-input-1-d849e34d61fb> in func1(a=1, b=0) 1 def func1(a, b): ----> 2 return a / b a = 1 b = 0 3 4 def func2(x): 5 a = x ZeroDivisionError: division by zero
이런 추가 정보들은 예외가 발생한 원인을 더 정확히 파악하는 데 큰 도움을 줍니다. 그렇다면 항상 Verbose 모드만 쓰면 되지 않을까요? 코드가 복잡해지면 이런 트레이스백 정보가 너무 길어져서 오히려 보기 불편할 수도 있습니다. 상황에 따라서는 Plain이나 Context 모드의 간결함이 문제를 확인하기에 더 편할 때도 있습니다.
디버깅: 트레이스백만으로는 부족할 때
대화형 디버깅을 위한 파이썬의 표준 도구는 pdb입니다. pdb를 사용하면 코드를 한 줄씩 실행하며 변수 값을 확인하고, 오류의 근본 원인을 추적합니다. IPython에서는 이보다 기능이 강화된 ipdb를 제공합니다.
두 디버거를 사용하는 방법은 무척 다양하므로 여기서는 핵심적인 부분만 다루겠습니다. 더 자세한 내용은 각 도구의 공식 문서를 참고해 보시기 바랍니다.
IPython에서 가장 편리한 디버깅 방법은 아마 %debug 매직 명령어일 것입니다. 예외가 발생한 직후 이 명령을 실행하면, 오류가 터진 그 지점에서 바로 대화형 디버깅 프롬프트가 열립니다. ipdb 프롬프트에서는 현재 스택의 상태를 살피고 변수 값을 확인하거나 직접 파이썬 명령어를 실행해 볼 수도 있습니다.
방금 발생한 예외 상황을 다시 확인해 보죠. %debug를 실행해 a와 b의 값을 확인한 뒤 quit을 입력해 세션을 마칩니다.
%debug> <ipython-input-1-d849e34d61fb>(2)func1()
1 def func1(a, b):
----> 2 return a / b
3
ipdb> print(a)
1
ipdb> print(b)
0
ipdb> quit
대화형 디버거의 기능은 이뿐만이 아닙니다. 실행 스택을 위아래로 오가며 각 단계에서의 변수 상태를 정밀하게 분석할 수도 있습니다.
%debug> <ipython-input-1-d849e34d61fb>(2)func1()
1 def func1(a, b):
----> 2 return a / b
3
ipdb> up
> <ipython-input-1-d849e34d61fb>(7)func2()
5 a = x
6 b = x - 1
----> 7 return func1(a, b)
ipdb> print(x)
1
ipdb> up
> <ipython-input-6-b2e110f6fc8f>(1)<module>()
----> 1 func2(1)
ipdb> down
> <ipython-input-1-d849e34d61fb>(7)func2()
5 a = x
6 b = x - 1
----> 7 return func1(a, b)
ipdb> quit
이를 통해 단순히 오류가 난 지점뿐만 아니라, 어떤 함수 호출을 거치며 문제가 발생했는지 빠르게 파악합니다.
만약 예외가 발생할 때마다 디버거가 자동으로 실행되길 원한다면, %pdb 매직 명령어로 자동 디버깅 기능을 활성화합니다.
%xmode Plain
%pdb on
func2(1)Exception reporting mode: Plain
Automatic pdb calling has been turned ON
Traceback (most recent call last): File "<ipython-input-9-569a67d2d312>", line 3, in <module> func2(1) File "<ipython-input-1-d849e34d61fb>", line 7, in func2 return func1(a, b) File "<ipython-input-1-d849e34d61fb>", line 2, in func1 return a / b ZeroDivisionError: division by zero
> <ipython-input-1-d849e34d61fb>(2)func1()
1 def func1(a, b):
----> 2 return a / b
3
ipdb> print(b)
0
ipdb> quit
마지막으로 특정 스크립트를 처음부터 단계별로 실행하며 디버깅하고 싶다면, %run -d 명령을 사용한 뒤 next 명령으로 코드 줄을 하나씩 넘기며 확인합니다.
주요 디버깅 명령어 요약
대화형 디버깅 시 자주 쓰이는 유용한 명령어들을 아래 표에 정리했습니다.
| 명령어 | 설명 |
|---|---|
l(ist) |
파일 내 현재 실행 위치를 표시 |
h(elp) |
명령어 목록을 보거나 특정 명령의 도움말을 확인 |
q(uit) |
디버거와 프로그램을 종료 |
c(ontinue) |
디버거를 종료하고 프로그램을 계속 실행 |
n(ext) |
다음 코드 줄로 이동 |
<Enter> |
바로 이전의 명령어 반복 |
p(rint) |
변수 값을 출력 |
s(tep) |
서브루틴(함수 내부)으로 진입 |
r(eturn) |
서브루틴에서 현재 함수를 마치고 복귀 |
더 상세한 내용은 디버거 내에서 help를 입력하거나 ipdb의 공식 문서를 참고하시기 바랍니다.