As our programs grow more complex with conditional logic (Post #25) and loops (Post #31, Post #34), it becomes increasingly likely that we will make mistakes. This is a normal and expected part of programming! A mistake in a program is called a bug, and the process of finding and fixing it is called debugging.
Sometimes a bug is a SyntaxError
, which stops the program from running at all. More often, it’s a logic error—the code runs without crashing, but it doesn’t do what you expect. How do we find these sneaky bugs?
In this post, we’ll introduce the first, most fundamental, and surprisingly powerful debugging technique: using print()
statements to trace your code’s execution.
The Detective’s Magnifying Glass: print()
The core idea of print debugging is simple: if you don’t know what your program is doing, ask it! By placing strategic print()
statements throughout your code, you can make your program report the values of its variables at key moments. This lets you “watch” your program run in slow motion and see exactly where things go wrong. Think of it as being a detective, and print()
is your magnifying glass to find clues.
A Case Study: The Buggy Summation
Let’s say we want to write a program that calculates the sum of all numbers from 1 to 5. The answer should be 15 (1 + 2 + 3 + 4 + 5). Here is our first attempt:
# Goal: Sum the numbers from 1 to 5
total = 0
number = 1
while number < 5:
total += number
number += 1
print(f"The final total is: {total}")
If you run this, it prints The final total is: 10
. The code runs, but the result is wrong. This is a classic logic error. The loop is clearly stopping too early, but why?
Using print()
to Trace the Variables
We suspect the problem is inside the while
loop. Let’s add print()
statements to see the values of total
and number
on each iteration of the loop, both before and after we add to the total.
total = 0
number = 1
print("--- Starting Debug Trace ---")
while number < 5:
print(f"Before adding: total is {total}, number is {number}")
total += number
number += 1
print(f"After adding: total is {total}, number is {number}")
print("--- Loop Finished ---")
print(f"The final total is: {total}")
Now, when we run the code, we get a detailed trace of what’s happening:
--- Starting Debug Trace ---
Before adding: total is 0, number is 1
After adding: total is 1, number is 2
Before adding: total is 1, number is 2
After adding: total is 3, number is 3
Before adding: total is 3, number is 3
After adding: total is 6, number is 4
Before adding: total is 6, number is 4
After adding: total is 10, number is 5
--- Loop Finished ---
The final total is: 10
By analyzing this output, we can see the bug clearly. The last thing that happens inside the loop is that number
is updated to 5
. The loop then goes back to the top and checks the condition while number < 5
. Since 5 < 5
is False
, the loop terminates immediately. The number 5
was never added to the total!
The Fix and the Cleanup
The fix is simple: we need the loop to run one more time when number
is 5. We can achieve this by changing the condition from <
to <=
.
# Goal: Sum the numbers from 1 to 5
total = 0
number = 1
while number <= 5: # The bug is fixed!
total += number
number += 1
print(f"The final total is: {total}")
Running this corrected code now gives the correct output: The final total is: 15
.
Once you’ve fixed the bug, you can remove or comment out your debugging print()
statements to clean up your code’s final output.
What’s Next?
Print debugging is a simple but incredibly effective technique. It’s a fundamental skill for any programmer. When in doubt, print it out! Seeing the state of your variables is the fastest way to understand what your code is actually doing versus what you think it’s doing.
Now that we have a basic strategy for finding mistakes, we can more confidently combine the concepts we’ve learned. In Post #44, we will look at a very common programming pattern: using an if
statement inside a for
loop to make decisions about each item in a sequence.
Author

Experienced Cloud & DevOps Engineer with hands-on experience in AWS, GCP, Terraform, Ansible, ELK, Docker, Git, GitLab, Python, PowerShell, Shell, and theoretical knowledge on Azure, Kubernetes & Jenkins. In my free time, I write blogs on ckdbtech.com