This article was published as a part of the Data Science Blogathon
Introduction
Everyone makes mistakes – even seasoned professional developers, and Python and great at catching them. Let’s see how it works.
Identifying errors is called debugging, and a debugger is a tool that helps to understand the cause of their occurrence. The ability to find and correct errors in the code is an important skill in the work of a programmer, do not neglect it.
IDLE (Integrated Development and Learning Environment) is a cross-platform integrated development and learning environment for Python, created by Guido van Rossum.
Use the debug control window
The main debugging interface in IDLE is the Debug Control window. You can open it by selecting the Debug → Debugger item in the interactive window menu.
Note: If debug is not on the menu bar, make sure the interactive window has focus.
Debug Control Window Overview
To see how the debugger works, let’s write a simple program without errors.
for i in range(1, 4): j = i * 2 print(f"i is {i} and j is {j}")
Save everything, open a debug window, and press F5 – execution has not finished.
The debug window will look like this:
Note that the bar at the top of the window contains the message:
> '__main__'.(), line 1: for i in range(1, 4):
Let’s decipher the code for i in range(1, 4): has not been launched yet, but ‘__main__’.module()reports that at the moment we are in the main section of the program, and not in the definition of the function.
Below the stack pane is the Locals pane, which lists weird things: __annotations__, __builtins__, __doc__, etc. are internal system variables that can be ignored for now. As the program runs, the variables declared in the code and displayed in this window will help you keep track of their values.
In the upper left corner of the window, there are five buttons: Go, Step, Over, Out and Quit – they control the movement of the debugger through the code.
In the following sections, you will learn what each of these buttons does.
Step button
Press Step and the debug window will look like this:
Note two differences. First, the message in the stack pane has changed:
> '_main_'.(), line 2: j = i * 2:
At this point, line 1 is executed and the debugger stops before executing line 2.
Second, a new variable i with a value of 1 in the Locals panel. The for loop on line 1 created a variable and assigned that value to it.
Continue pressing the Step button to step through the code line by line and watch what happens in the debugger window. When you get to the line print(f” i is {i} and j is {j}”), you can see the output displayed in the interactive window one chunk at a time.
The important thing here is that you can keep track of the growing values of i and j as you go through the for a loop. This is a useful feature of finding the source of errors in the code. Knowing the meaning of each variable in each line of code can help pinpoint the problem area.
Breakpoints and the Go button
Often you know that an error should appear in a certain piece of code, but you don’t know where exactly. Breakpoints tell the debugger when to pause code execution so you can take a look at the current state of the program.
To set a breakpoint, right-click (Ctrl for Mac) the line of code you want to pause and choose Set Breakpoint – IDLE will highlight the line in yellow. To remove it, select Clear Breakpoint.
Set a breakpoint on the line with the print () statement. Now, see the editor window:
Save and run. As before, the stacked bar indicates that the debugger is running and waiting for line 1. To move ahead just press the Go button:
Now on the stack panel, there is information about the execution of line 3:
> '_main_'.(), line 3: print(f"i is {i} and j is {j}")
In the Locals panel, we will see that the variables i and j have values 1 and a couple of, respectively. Click the Go button and ask the debugger to run the code until the breakpoint or the top of the program. Press return – the debug window now seems like this:
The stack pane displays the same message as before – the debugger is waiting for line 3. However, the values of i and j are now 2 and 4. Press the button a third time. Now i and j are 3 and 6. Pressing Go again exits the program.
Over and Out
The Over button works like a combination of Step and Go — it steps over a function or loop. In other words, if you are going to get into a function using the debugger, you do not need to run the code of this function – the Over button will lead directly to the result of its execution.
Likewise, if you’re already inside a function or loop, the Out button executes the remainder of the code inside the body of the function or loop then stops.
In the next section, we will explore some of the errors and learn how to fix them using IDLE.
Fighting bugs
Let’s take the example of an easy and buggy program.
The add_underscores () method defines below as accepting a String as an argument and returning a new string consisted of underscores before and after each character. For example, it add_underscores(“python”)will return «_p_y_t_h_o_n_».
Here’s the broken code:
def add_underscores(word): new_word = "_" for i in range(len(word)): new_word = word[i] + "_" return new_word phrase = "hello" print(add_underscores(phrase))
Enter this code into the editor, save and press F5. The expected output is _h_e_l_l_o_, but o_ is printed instead.
If you find what the problem is, do not fix it. Our goal is to learn how to use IDLE for this.
Let’s consider 4 stages of bug search:
-
guess where the error might be;
-
set a breakpoint and check the code line at a time;
-
define the line and make changes;
-
repeat steps 1-3 until the code works.
Step 1: Guess
You won’t be able to pinpoint the exact location of the error at first, but it’s usually easier to logically imagine which section of the code to look at.
Note that the program is divided into two sections: the definition of the add_underscores () function and the main block, which defines a variable with the value “hello” and outputs the result.
Now, let’s see the code for the main section:
phrase = "hello" print(add_underscores(phrase)) Obviously, everything is fine here and the problem should be in the definition of the function: def add_underscores(word): new_word = "_" for i in range(len(word)): new_word = word[i] + "_" return new_word
The first line creates the new_word variable with the value “_”. Miss, the problem is somewhere in the body of the for a loop.
Step 2: breakpoint
Once you’ve identified where the error might be, set a breakpoint at the beginning of the for loop to keep track of what’s going on inside the code:
Let’s start. Execution stops at the line with the function definition.
Click the Go button to execute the code up to the breakpoint:
The code stops before the for loop in the add_underscores () function. Note that the Locals panel displays two local variables – a word with the value “hello”, and new_word with the value “_”
Click the Step button to enter the for a loop. The debug window changes and therefore the new i variable with a worth of 0 is displayed within the Locals panel:
The variable i is a counter for the for loop that you can use to keep track of the currently active iteration.
Press the Step button again and look at the Locals panel – the new_word variable is set to “h_”:
This is wrong and the reason for this is at first new_word the value is “_”, on the second iteration the value is “_h_”. If we press Step a few more times, we will see that new_word contains the value e_, then l_, and so on.
Step 3: Identify the error and fix it
As we have already found out, at each iteration of the loop, new_word is overwritten with the next character in the line “hello” and an underscore. Since there is only one line of code inside the loop, the problem should be right there:
new_wor = word[i] + "_"
The code tells Python to get the next word character, attach an underscore, and assign the newline to the new_word variable. This is exactly the wrong behaviour that we have observed.
To fix everything, you need to combine the word[i] + “_” with the existing value new_word. Click the Quit button in the debug window, but do not close it. Open an editor window and change the line inside the for loop to the following:
new_word = new_word + word[i] + "_"
Debugger only toggled when idle!
Always press the Go or Quit button when you finish debugging, otherwise, you may have problems restarting it.
Step 4: Repeat steps 1-3 until the error goes away
Save changes in the program and run it again. In the debug window, click the Go button to execute the code up to the breakpoint. Press Step several times and see what happens to the new_word variable at each iteration – everything works needless to say. Sometimes it is necessary to repeat this process several times before the error is fixed.
Alternative ways to find errors
Using the debugger can be tricky and time-consuming, but it is the most reliable way to find bugs in your code. However, debuggers are not always available. In situations like this, you’ll use print debugging to seek out bugs in your code. PD uses the print () function to display text to the console indicating where the program is executing and the state of the variables.
Just as an example, the below code can be added at the end of the loop, for debugging:
print(f"i = {i}; new_wor = {new_wor}")
The modified code will look like this:
def add_underscores(word): new_wor = "_" for i in range(len(word)): new_wor = word[i] + "_" print(f"i = {i}; new_word = {new_wor}") return new_wor phrase = "hello" print(add_underscores(phrase))
The output should look like this:
i = 0; new_wor = h_ i = 1; new_wor = e_ i = 2; new_wor = l_ i = 3; new_wor = l_ i = 4; new_wor = o_ o_
PD works but has several disadvantages compared to debugging with a debugger. You should run the entire program every time you want to check the values of variables, and remember to remove calls to print () functions.
One way to improve our loop is to iterate over characters in a word:
def add_underscores(word): new_wor = "_" for letter in word: new_wor = new_wor + letter + "_" return new_wor
Conclusion
Now you know all about DLE debugging. You can use this principle with various debuggers.
In this text, we covered the subsequent topics:
-
using the debug control window;
-
setting a breakpoint for a deep understanding of how the code works;
-
use of the Step, Go, Over, and Out buttons;
Don’t stop learning and practice debugging – it’s fun! and reach me on LinkedIn at https://www.linkedin.com/in/shivani-sharma-aba6141b6/
The media shown in this article are not owned by Analytics Vidhya and are used at the Author’s discretion.
Related
- "
- active
- All
- analytics
- AREA
- article
- body
- Bug
- bugs
- Cause
- change
- code
- Couple
- cross-platform
- Current
- Current state
- developers
- Development
- editor
- Environment
- etc
- execution
- Feature
- fine
- First
- Fix
- Focus
- function
- great
- Growing
- here
- Highlight
- How
- How To
- HTTPS
- identify
- information
- interactive
- IT
- lead
- LEARN
- learning
- Line
- Lists
- local
- location
- mac
- Media
- move
- open
- Other
- press
- Program
- Python
- Run
- running
- Science
- Search
- set
- Simple
- So
- start
- State
- Statement
- system
- tells
- The Source
- time
- top
- Topics
- track
- value
- Watch
- within
- words
- Work
- works
- worth