Much of the material in this document is taken from Appendix F in the book A Primer on Scientific Programming with Python, 4th edition, by the same author, published by Springer, 2014.
A debugger is a program that can help you to find out what is going on in a computer program. You can stop the execution at any prescribed line number, print out variables, continue execution, stop again, execute statements one by one, and repeat such actions until you have tracked down abnormal behavior and found bugs.
Here we shall use the debugger to demonstrate the program flow of the code Simpson.py (which can integrate functions of one variable with the famous Simpson's rule). You are strongly encouraged to carry out the steps below on your computer to get a glimpse of what a debugger can do.
Go to the folder
where the program
If you use the Spyder Integrated Development Environment, choose Debug on the Run pull-down menu. If you run your programs in a plain terminal window, start IPython:
Run the program
Simpson.py with the
debugger on (
In : run -d Simpson.py
We now enter the debugger and get a prompt
After this prompt we can issue various debugger commands. The most important ones will be described as we go along.
continue or just
c to go to the first line
in the file. Now you can see a printout of where we are in the
1---> 1 def Simpson(f, a, b, n=500): 2 """ 3 Return the approximation of the integral of f
Each program line is numbered and the arrow points to the next line to be executed. This is called the current line.
You can set a break point where you want the program to stop
so that you can examine variables and perhaps follow the execution
closely. We start by setting a break point in the
ipdb> break application Breakpoint 2 at /home/.../src/funcif/Simpson.py:30
You can also say
break X, where
X is a line number in the
Continue execution until the break point by writing
c. Now the program stops at line 31 in the
ipdb> c > /home/.../src/funcif/Simpson.py(31)application() 2 30 def application(): ---> 31 from math import sin, pi 32 print 'Integral of 1.5*sin^3 from 0 to pi:'
step or just
s executes one statement at a time:
ipdb> s > /home/.../src/funcif/Simpson.py(32)application() 31 from math import sin, pi ---> 32 print 'Integral of 1.5*sin^3 from 0 to pi:' 33 for n in 2, 6, 12, 100, 500: ipdb> s Integral of 1.5*sin^3 from 0 to pi: > /home/.../src/funcif/Simpson.py(33)application() 32 print 'Integral of 1.5*sin^3 from 0 to pi:' ---> 33 for n in 2, 6, 12, 100, 500: 34 approx = Simpson(h, 0, pi, n)
s reaches the call to
Simpson, and a new
s steps into the function
ipdb> s --Call-- > /home/.../src/funcif/Simpson.py(1)Simpson() 1---> 1 def Simpson(f, a, b, n=500): 2 """ 3 Return the approximation of the integral of f
Type a few more
s to step ahead of the
Examining the contents of variables is easy with the
ipdb> print f, a, b, n <function h at 0x898ef44> 0 3.14159265359 2
We can also check the type of the objects:
ipdb> whatis f Function h ipdb> whatis a <type 'int'> ipdb> whatis b <type 'float'> ipdb> whatis n <type 'int'>
Set a new break point in the
application function so that we
can jump directly there without having to go manually through all the
statements in the
Simpson function. To see line numbers and
corresponding statements around some line with number
list X. For example,
ipdb> list 32 27 def h(x): 28 return (3./2)*sin(x)**3 29 30 from math import sin, pi 31 2 32 def application(): 33 print 'Integral of 1.5*sin^3 from 0 to pi:' 34 for n in 2, 6, 12, 100, 500: 35 approx = Simpson(h, 0, pi, n) 36 print 'n=%3d, approx=%18.15f, error=%9.2E' % \ 37 (n, approx, 2-approx)
We set a line break at line 35:
ipdb> break 35 Breakpoint 3 at /home/.../src/funcif/Simpson.py:35
c continues execution up to the next break point, line 35.
n is like
in that the current line is executed, but the execution does not
step into functions, instead the function calls are just performed
and the program stops at the next line:
ipdb> n > /home/.../src/funcif/Simpson.py(36)application() 3 35 approx = Simpson(h, 0, pi, n) ---> 36 print 'n=%3d, approx=%18.15f, error=%9.2E' % \ 37 (n, approx, 2-approx) ipdb> print approx, n 1.9891717005835792 6
disable X Y Z disables break points with numbers
Z, and so on.
To remove our three break points and continue
execution until the program naturally stops, we write
ipdb> disable 1 2 3 ipdb> c n=100, approx= 1.999999902476350, error= 9.75E-08 n=500, approx= 1.999999999844138, error= 1.56E-10 In :
At this point, I hope you realize that a debugger is a very handy tool for monitoring the program flow, checking variables, and thereby understanding why errors occur.