Debugging in Python
One of the reasons why I love the Python programming language is because of how easy debugging is. You don't need a full blown IDE to be able to debug your Python application. We will go through the process of debugging a simple Python script using the
pdb module from the Python standard library, which comes with most installation of Python.
Let's take a look at the following simple snippet:
def funcA(first_val, second_val): result = (first_val*2) - (second_val/4) return result def functionB(first_val=23, last_val=72): response = funcA(first_val, last_vale) result = response * first_val / 7 return result functionB(33,88) # we are evaluating the funciton.
If we try running the snippet above, we would get an error:
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in functionB NameError: global name 'last_vale' is not defined
To find out what is wrong with this snippet, we need to know where we should place our breakpoint. A breakpoint tells the Python interpreter to pause execution at a particular point in our application.
From the error message above, we can infer that the problem is coming from the
functionB function. But depending on our expertise, we might not be sure what is causing the error.
To debug the problem, we would add a breakpoint to the start of our
# we would place our break point here import pdb pdb.set_trace() response = funcA(first_val, last_vale) result = response * first_val / 7 return result
The breakpoint in this case is the two line
import pdb; and
pdb.set_trace(). With these two lines in place, if we try running our application again, we would get an output like this
The interface looks similar to that of the interactive shell that Python provides. We can test out the values passed into the function by typing them out:
To step to the next line, we use the key
n, which means
next, to step down the code line by line
We can see from the above that as we moved to the next line, the error we encountered earlier on, came up again. So we are certain that the problem in our code happens on the line which we just ran.
To get python to continue execution of the program, we type
c which means
continue and the program executes as usual.
Now assuming we fixed our implementation by ensuring that the correct name of the variable is used and removed the breakpoint because we don't want the program to pause
def funcA(first_val, second_val): result = (first_val * 2) - (second_val / 0) return result def functionB(first_val=23, last_val=72): # we would place our break point here response = funcA(first_val, last_val) result = response * first_val / 7 return result functionB(33, 88)
We would run into a different kind of error this time
$ python sample.py Traceback (most recent call last): File "sample.py", line 13, in <module> functionB(33, 88) File "sample.py", line 8, in functionB response = funcA(first_val, last_val) File "sample.py", line 2, in funcA result = (first_val * 2) - (second_val / 0) ZeroDivisionError: integer division or modulo by zero
We might not be sure where the error is coming from if we are just getting familar with python but with
pdb we can progress incrementally to where the error occurs.
We know that the starting point of our application is in
functionB function so we would place our breakpoint there and step through the application line by line
We are already familiar with
n moving to the next line. But now we are seeing
s. This means
step which moves the flow of control into the
functionA we keep on pressing
n line by line till we get to the part of our code that throws the error.
There are actually more commands, all of which can be explored at https://docs.python.org/2/library/pdb.html. But For your day to day debugging needs,
c is all you need.
One thing we should keep in mind should we choose to debug our application this way is to ensure that we don't use single word values as variable names in our application.
Take for instance
import pdb pdb.set_trace() n= 84 s = 45 c = 23
If we wanted to navigate to the next line and we typed
n, we would run into a conflict because
n has special meaning in
pdb and our variable is also named