Debugging
A broken program
We have a Python program called guess.py:
from random import randint
answer = randint(0, 1)
n = input("Guess: 0 or 1? ")
if n == answer:
print("Correct!")
else:
print(f"Incorrect. The answer was {answer}.")
We can run this program by typing python, python3, or py (if on Windows) from our system command prompt followed by guess.py (as long as we’re in the same directory as that file):
$ python guess.py
This program is supposed to prompt the user to guess either 0 or 1 and then tell them if their answer was correct.
$ python guess.py
Guess: 0 or 1? 0
Incorrect. The answer was 1.
The problem is that our program always says the answer is incorrect.
$ python guess.py
Guess: 0 or 1? 0
Incorrect. The answer was 0.
breakpoint
Let’s try to investigate what’s going on in this program.
We’ll do this by using the Python Debugger (a.k.a. PDB).
We can start the Python debugger with the built-in breakpoint function.
Let’s add a call to breakpoint near the top of our Python program:
from random import randint
breakpoint()
answer = randint(0, 1)
n = input("Guess: 0 or 1? ")
if n == answer:
print("Correct!")
else:
print(f"Incorrect. The answer was {answer}.")
Now when we run our program, we’ll see a (Pdb) prompt:
$ python guess.py
> /home/trey/guess.py(5)<module>()
-> answer = randint(0, 1)
We can use the l command to list the file that we’re on:
(Pdb) l
1 from random import randint
2
3 breakpoint()
4
5 -> answer = randint(0, 1)
6 n = input("Guess: 0 or 1? ")
7
8 if n == answer:
9 print("Correct!")
10 else:
11 print(f"Incorrect. The answer was {answer}.")
And we can use the n command to run the next line of code:
(Pdb) n
> /home/trey/guess.py(6)<module>()
-> n = input("Guess: 0 or 1? ")
We can also run statements and see their results.
Here we’re looking at the value for the answer variable:
(Pdb) answer
1
Let’s run the next line and then respond to the user input prompt:
(Pdb) n
Guess: 0 or 1? 1
> /home/trey/guess.py(8)<module>()
-> if n == answer:
(Pdb)
We have a problem right now.
We would like to see the value for the n variable.
But n is a PDB command, so if we type n we’ll go to the next line.
We can fix this in a few different ways:
We could put a
!character at the beginning of our line to tell PDB that our statement is a Python statement and not a PDB commandWe could run the
interactcommand which would drop us into a regular Python REPL where we can run any commands we’d like as usual
Let’s use interact:
(Pdb) interact
*interactive*
>>>
Now that we’re in a Python REPL we could use the built-in dir function to list all our variables:
>>> dir()
['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'answer', 'n', 'randint']
Let’s look at the answer and n variables:
>>> answer
1
>>> n
'1'
Ah hah!
The problem is that answer is a number while n is a string.
I’ll leave it up to you to fix our program.
We can use exit to exit our program:
>>> exit()
Note
On Python 3.6 and below, the breakpoint function didn’t exist yet.
You’ll need to type import pdb ; pdb.set_trace() to start the Python debugger on Python 3.6 and earlier Python versions.
More PDB Commands
Below are the pdb commands I usually use.
The characters in parenthesis are optional (so n and next do the same thing):
n(ext): Run the next line of codes(tep): Step into the current line of code (step into a function call usually)r(eturn): Return from the current functionc(ontinue): Exit PDB, continuing until the next breakpoint or the end of the programl(ist): List the surrounding code linesinteract: Enter interactive mode, which starts a Python REPL session