Debugging with Thonny¶
Programming mistakes¶
Everyone makes mistakes—even seasoned professional developers!
Python is good at catching mistakes like syntax errors and run-time errors. Unfortunately, there is a third type of error that you may have already experienced. Logic errors occur when a valid program doesn’t do what the programmer intended.
For example, type the code below and save it has buggy_code.py
.
For this tutorial download buggy_code.py
file and save it to your lesson folder.
1def add_underscores(word):
2 new_word = "_"
3 for index in range(len(word)):
4 new_word = word[index] + "_"
5 return new_word
6
7phrase = "hello"
8print(add_underscores(phrase))
The expected output is _h_e_l_l_o_
. Run it and you will see it actually outputs o_
.
Logic errors cause unexpected behaviours called bugs. Debugging is process of removing bugs. A debugger is a tool that helps the programmer hunt down bugs and understand what’s happening.
Knowing how to find and fix bugs in your code is a skill that you will use for your entire coding career!
Using Thonny’s Debugger¶
To debug buggy_code.py
we need to understand the debugging tools we have at our disposal. Thonny has a debugger built-in, but before we explore it, we need to make sure you have the correct setup.
Open the View menu and ensure there is a tick beside both Stack and Variables.
To enter into Thonny’s Debugger click on the Debug button.
Controlling the debugger¶
To see how the debugger works, let’s start by writing a simple program without any bugs.
Type the following into Thonny and save it as debug_a.py
:
1names = ["michelle", "nicole", "simone", "emma"]
2
3for name in names:
4 name = name.capitalize()
5 print(f"Hello {name} how are you this morning")
Now start Thonny’s debugger.
Your Thonny should now look like the image below:
Code Panel: Thonny has paused the execution of the code. The yellow highlight shows the code that Python will execute next.
Variables Panel: Since the program hasn’t assigned any values, it shows no variables.
Shell Panel: %Debug launches is the command that launches the program (debug_a.py).
Stack Panel: Shows the current function and module that is running.
Something else has happened, other debugging buttons are now available.
Lets see how they work.
Debugging a Logic Error¶
First let’s look closely at buggy_code.py
:
1def add_underscores(word):
2 new_word = "_"
3 for index in range(len(word)):
4 new_word = word[index] + "_"
5 return new_word
6
7phrase = "hello"
8print(add_underscores(phrase))
Guess the bug is location¶
The first step is to identify the section of code that is likely to contain the bug. You may not be able to identify exactly where the bug. So, make a reasonable guess about which section of your code has an error.
Notice that there are two distinct sections of the program:
a function definition →
lines 1
to5
main code block
line 7
→ defines a variablephrase
with the value"hello"
line 8
→ then prints the result of callingadd_underscores(phrase)
Look at the main section:
7phrase = "hello"
8print(add_underscores(phrase))
Do you think the problem could be here? It doesn’t look like it, right? Everything about those two lines of code looks good. So, the problem must be in the function definition:
1def add_underscores(word):
2 new_word = "_"
3 for index in range(len(word)):
4 new_word = word[index] + "_"
5 return new_word
The first line of code inside the function creates a variable new_word
with the value "_"
. You’re all good there, so you can conclude that the problem is somewhere in the body of the for
loop.
Set a breakpoint to inspect code¶
Now that we’ve identified where the bug must be, set a breakpoint at the start of the for loop. This way we can trace out exactly what’s happening inside the loop with the debugging tool:
Click the Debug button to launch Thonny’s debugger. Thonny will run the code until it hits the breakpoint. Your IDE should look like the image below. There are some new features we haven’t seen before.
additional debugging window:
notice that Thonny has launched a new debugging window for
add_underscores('hello')
function.Whenever a Python enters a new scope Thonny will launch a debugging window for that scope.
The values stored in the local variables are at the bottom of the new window.
Local variables are variables that only the current function can see.
multiple stack values:
in the stack panel you will now see two values.
first value
refers to the main section second value refers to the add_underscores function section
This shows us that the program is at:
line 8
in the main programline 3
of the add_underscores function section.
Stack timeline
line 8
in the main module called theadd_underscores
functionPython pauses the main section at
line 8
at wait for theadd_underscores
function to finishWhen the function finishes, the main section will continue from
line 8
onwards.
Back to debugging. Notice the add_underscores
window displays the word and new_word variables. Currently, word
has the value 'hello'
and new_word
has the value '_'
, as expected.
Let’s look further.
Click:
Step into once
Step over twice
You should end up with new_word = word[index] + "_"
highlighted and ready to process (like below).
Notice the local variable index is storing 0. This is correct for the first iteration of the loop.
Hint
If you can’t see the index variable, you may need to resize the Local variables panel.
Now click Step over to execute new_word = word[index] + "_"
and have a look at the results.
Notice that new_word is now storing 'h_'
, whereas we want it to be storing '_h_'
. What happened there? We have found our error location.
Now that we know the error is in the new_word = word[index] + “_” code. Let’s investigate that code and see exactly what happened.
First click Stop and then Debug again.
Click:
Step into once
Step over twice
You should now have the problem code highlighted (like below).
This time we will step into the code and see what happens.
First Step into and everything looks good.
Second Step into everything is still fine.
Third Step into, all good.
Keep click Step into and follow what is happening in the Local variables. Stop when your add_underscores('hello')
is in the state below:
Looking closely at the debugging code. You will notice:
Python is about to assign the value of
'h_'
tonew_word
This is not right!
We want it to assign
'_h_'
tonew_word
Now we know exactly where the problem is, we need to work out why this is a problem.
add_underscores()
is supposed to insert a _
between each letter. It does this by repetitively concatenating the next letter and _
to the value stored in new_word.
But our code is overwriting new_word
. We are loosing all the previously processed letters.
What we need to do is concatenate the current value of new_word
in front of the processed letter and _.
The line should read new_word = new_word + word[index] + "_"
Stop the debugging, make the change to the code below.
Run the program normally. Is the output _h_e_l_l_o_
?
Problem solved. You have now successfully debugged faulty code.