Sometimes when debugging Python code, it is useful to be able to see the values of the variables at each step in its execution. This can be done with a debugging tool in your IDE, but sometimes it is enough to simply add some print()
commands to your code at strategic points, to output these values.
For example, in the 100 Doors Challenge, there is something interesting happening with the loop counters, as the outer loop counter is used to determine the range for each inner loop. This can be quite confusing to think about, but some well placed print()
commands can help to clarify what is happening.
To keep the output manageable, I’ve reduced the problem to a smaller version (which is a very useful problem solving technique in general). So instead of 100 doors, we will work with only 10 for now.
Python Code Listing for 10 Doors Challenge
doors = [False] * 11 # so we can start at door 1. We will ignore index 0
for i in range(1, 11):
# for the second pass, x = 2, so we start at door 2, for the 3rd pass we start at door 3 etc.
for j in range(i, 11, i):
doors[j] = not doors[j] # using `not` to invert the Boolean value
# Print out just the positions of the open doors
for i in range(1, 11):
if doors[i] is True: # Or just if doors[i]:
print(i)
Now lets add some output to help us to see what is happening internally in this program. Just before we start though, notice that Python allows several ways of formatting output.
For example, we could use something like
i= 1
print("Value of i: ", i)
which would give output:
Value of i: 1
Or we could use the the nifty f-string option, which performs variable interpolation, which is just a posh name for “substitution”. This would looks like this:
i= 1
print(f"Value of i: {i}")
Output:
Value of i: 1
f-strings are very cool, and if you are using Python 3.6 or above then I thoroughly recommend using them. There are some details of how to get the most from them, but for now just use them as shown in this article and you’ll be fine.
Python Code Listing for 10 Doors Challenge with Extra Output
OK, so back to the issue of tracking what’s happening as the the algorithm executes. Try running this amended version.
doors = [False] * 11 # so we can start at door 1. We will ignore index 0
for i in range(1, 11):
# for the second pass, x = 2, so we start at door 2, for the 3rd pass we start at door 3 etc.
for j in range(i, 11, i):
print(f"i: {i}; j:{j}; step size: {i}. Toggling door number {j}.")
doors[j] = not doors[j] # using `not` to invert the Boolean value
# Print out just the positions of the open doors
print("Algorithm has finished.")
for i in range(1, 11):
if doors[i] is True: # Or just if doors[i]:
print(f"Door number {i} remains open.")
This is the output:
i: 1; j:5; step size: 1. Toggling door number 5.
i: 1; j:6; step size: 1. Toggling door number 6.
i: 1; j:7; step size: 1. Toggling door number 7.
i: 1; j:8; step size: 1. Toggling door number 8.
i: 1; j:9; step size: 1. Toggling door number 9.
i: 1; j:10; step size: 1. Toggling door number 10.
i: 2; j:2; step size: 2. Toggling door number 2.
i: 2; j:4; step size: 2. Toggling door number 4.
i: 2; j:6; step size: 2. Toggling door number 6.
i: 2; j:8; step size: 2. Toggling door number 8.
i: 2; j:10; step size: 2. Toggling door number 10.
i: 3; j:3; step size: 3. Toggling door number 3.
i: 3; j:6; step size: 3. Toggling door number 6.
i: 3; j:9; step size: 3. Toggling door number 9.
i: 4; j:4; step size: 4. Toggling door number 4.
i: 4; j:8; step size: 4. Toggling door number 8.
i: 5; j:5; step size: 5. Toggling door number 5.
i: 5; j:10; step size: 5. Toggling door number 10.
i: 6; j:6; step size: 6. Toggling door number 6.
i: 7; j:7; step size: 7. Toggling door number 7.
i: 8; j:8; step size: 8. Toggling door number 8.
i: 9; j:9; step size: 9. Toggling door number 9.
i: 10; j:10; step size: 10. Toggling door number 10.
Algorithm has finished.
Door number 1 remains open.
Door number 4 remains open.
Door number 9 remains open.
I think you’ll agree this makes it very clear what is happening as the program goes through its loops and statements. As you study more complex algorithms you may well find that a significant amount of the time you spend either implementing or trying to understand a particular algorithm will on pondering the kind of information shown above.
A well placed
print()
command can shed a lot of light on how an algorithm works (or doesn’t work).
Using the IDLE Debugger to Trace Algorithms
Another way of tracing the values of variables during program execution is to use a debugging tool, which comes with an IDE (Integrated Development Environment).
With IDLE (the basic IDE which comes packaged with Python), the steps are as follows:
- Enable line numbers using the options menu.
- Run the module (file) containing your program.
- Select debugger from the debug menu.
- Go back to the window containing your program.
- Set a break-point where you want the program to pause, using the right-click menu
- Run the module again.
You can now step thorough your program using the buttons on the debugger window, and try to make sense of the output. Note that stepping over only applies when functions are at play. It allows you to step over a whole function call without diving into the details of the execution of its individual lines.
Personally I find the IDLE debugger confusing and unintuitive, so I don’t use it. You might well have a better experience using an online visualisation tool such as the one described here: How to Trace Python Algorithms with a Visualisation Tool.
Using PyCharm to Debug your code
Using PyCharm gives a better experience when debugging code. The image below shows the 100 Doors program in mid-debug. I have highlighted some of the key features using a a green pen.
- A breakpoint on line 5
- The Run in Debug mode button
- The contents of the
doors
list on display - The buttons for stepping through the code.
This article has discussed how to trace variable values during the execution of algorithms written in Python. Most Python IDEs provide debugging tools to help with this, but you may well find that, at least for the time being, using print()
commands is quite sufficient for your needs.