../_images/book_cover.jpg

This notebook contains an excerpt from the Python Programming and Numerical Methods - A Guide for Engineers and Scientists, the content is also available at Berkeley Python Numerical Methods.

The copyright of the book belongs to Elsevier. We also have this interactive book online for a better learning experience. The code is released under the MIT license. If you find this content useful, please consider supporting the work on Elsevier or Amazon!

< 10.4 Type Checking | Contents | 10.6 Summary and Problems >

Debugging

Debugging is the process of systematically removing errors, or bugs, from your code. Python has functionalities that can assist you when debugging. The standard debugging tool in Python is pdb (Python DeBugger) for interactive debugging. It lets you step through the code line by line to find out what might be causing a difficult error. The Ipython version of this is ipdb (IPython DeBugger). We won’t cover too much about it here, you can check out the documentation for details. In this section, basic debug steps in Jupyter notebook will be introduced. We will show you how to use two really useful magic commands %debug and %pdb to find out the trouble code.

There are two ways you could debug your code, (1) activate the debugger after we run into an exception; (2) activate debugger before we run the code.

Activate the debugger after we run into an exception

If we run the code which stops at an exception, we could call %debug. For example, we have a function that squares the input number and then add itself, as shown below:

def square_number(x):
    
    sq = x**2
    sq += x
    
    return sq
square_number('10')
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-2-e0b77a2957d5> in <module>
----> 1 square_number('10')

<ipython-input-1-3fc6a3900214> in square_number(x)
      1 def square_number(x):
      2 
----> 3     sq = x**2
      4     sq += x
      5 

TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'

After we have this exception, we could activate the debugger by using the magic command - %debug, which will open an interactive debugger for you. You can type in commands in the debugger to get useful information.

%debug
> <ipython-input-1-3fc6a3900214>(3)square_number()
      1 def square_number(x):
      2 
----> 3     sq = x**2
      4     sq += x
      5 

ipdb> h

Documented commands (type help <topic>):
========================================
EOF    cl         disable  interact  next    psource  rv         unt   
a      clear      display  j         p       q        s          until 
alias  commands   down     jump      pdef    quit     source     up    
args   condition  enable   l         pdoc    r        step       w     
b      cont       exit     list      pfile   restart  tbreak     whatis
break  continue   h        ll        pinfo   return   u          where 
bt     d          help     longlist  pinfo2  retval   unalias  
c      debug      ignore   n         pp      run      undisplay

Miscellaneous help topics:
==========================
exec  pdb

ipdb> p x
'10'
ipdb> type(x)
<class 'str'>
ipdb> p locals()
{'x': '10'}
ipdb> q

You can see that after we activate the ipdb, we could type commands to get the information of the code. The example above, I typed the following commands:

  • h to get a list of help

  • p x to print the value of x

  • type(x) to get the type of x

  • p locals() to print out all the local variables

There are some most frequent commands you can type in the pdb, like:

  • n(ext) line and run this one

  • c(ontinue) running until next breakpoint

  • p(rint) print varibles

  • l(ist) where you are

  • ‘Enter’ Repeat the previous command

  • s(tep) Step into a subroutine

  • r(eturn) Return out of a subroutine

  • h(elp) h

  • q(uit) the debugger

Activate debugger before we run the code

We could also turn on the debugger before we even run the code and then turn it off after we finish running the code.

%pdb on
Automatic pdb calling has been turned ON
square_number('10')
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-5-e0b77a2957d5> in <module>
----> 1 square_number('10')

<ipython-input-1-3fc6a3900214> in square_number(x)
      1 def square_number(x):
      2 
----> 3     sq = x**2
      4     sq += x
      5 

TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'
> <ipython-input-1-3fc6a3900214>(3)square_number()
      1 def square_number(x):
      2 
----> 3     sq = x**2
      4     sq += x
      5 

ipdb> p x
'10'
ipdb> c
# let's turn off the debugger
%pdb off
Automatic pdb calling has been turned OFF

Add a breakpoint

It is often very useful to insert a breakpoint into your code. A breakpoint is a line in your code at which Python will stop when the function is run.

import pdb
def square_number(x):
    
    sq = x**2
    
    # we add a breakpoint here
    pdb.set_trace()
    
    sq += x
    
    return sq
square_number(3)
> <ipython-input-8-e48ec2675aea>(8)square_number()
-> sq += x
(Pdb) l
  3  	    sq = x**2
  4  	
  5  	    # we add a breakpoint here
  6  	    pdb.set_trace()
  7  	
  8  ->	    sq += x
  9  	
 10  	    return sq
[EOF]
(Pdb) p x
3
(Pdb) p sq
9
(Pdb) c
12

We could see after we added pdb.set_trace(), the program stops at this line, and activate the pdb debugger. We could check all the variable values that assigned before this line. And use the command c to continue the execution.

Using the Python’s debugger can be extremely helpful in finding and fixing errors in your code. We encourage you to use the debugger for large programs.

< 10.4 Type Checking | Contents | 10.6 Summary and Problems >