By now, you’ve started to encounter bugs in your code.
These typically fall into two categories:
syntax and runtime errors (Python prints errors when you run your code)
logical errors (Python prints no errors, but your code does not have the desired behavior)
Syntax and runtime errors show up as Python executes your code. This actually makes syntax errors more easy to identify and resolve. Consider the two snippets of code below, which contain syntax errors.
bug:str = "ant
if bug[3] == "t":
print( "The last letter in your bug is t" )
else
bug = "butterfly"
print( "Your bug has wings!" )
bug:str = "ant"
if bug[2] == "t":
print( "The last letter in your bug is t" )
else
bug = "butterfly"
print( "Your bug has wings!" )
When your program runs without printing any errors, but does not have the expected behavior, we call this a "logical bug." These are usually the hardest to track down and resolve, as they occur where your plan doesn't match your implementation. If you don't have a clear plan, then things become that much harder!
bug:str = "caterpillar"
if bug[2] == "t":
print( "The last letter in your bug is t" )
else:
bug = "butterfly"
print( "Your bug has wings!" )
The logical bug is that the word "caterpillar" does not end in "t", yet the condition evaluates to true. To fix this, we can change the index being used for accessing the last letter of the word.
bug:str = "caterpillar"
if bug[len(bug)-1] == "t":
print( "The last letter in your bug is t" )
else:
bug = "butterfly"
print( "Your bug has wings!" )
Tracing your code (sometimes I call this “drawing memory”) is a good way to investigate what values your variables in your program have.
Try it out, then use Python tutor to check your understanding.
x = 3
y = 3
z = 1
if ( y % x == z ) or ( y * x == z ) :
y = x + z
else :
y = x - z
print ( "y is " + str (y) )
One of the most universally used debugging techniques is strategic placement of print statements. By adding these to our code, we can try to isolate the line or block that is not doing what we intended (and commented!) A print statement can
reveal and log what is in memory during the execution of our code
help identify which code is being executed and in what order
Put a print statement after any assignment to a variable that you think is involved in the bug
Place it RIGHT AFTER.
Make sure to match indentation
Need more info? Try placing another one RIGHT BEFORE
Print out the name of the variable you’re printing out, like this:
print( "x: " + str(x) )
OR
print( f"x: {x}" )
Print out information about where you are in the code, like this:
print( f"Within the first if branch, x: {x}") )
import random
def maxValue( values:list ) -> int:
""" Determine and return the max value of a list of positive numbers. """
currentMax:int = -1
for value in values:
if value > currentMax:
currentMax = values
return currentMax
randomValues:list = []
for i in range(random.randint(0,4)):
randomValues.append( random.randint( 0, 20 ) )
print(f"maxValue({randomValues}) is {maxValue(randomValues)}")
import random
def maxValue( values:list ) -> int:
""" Determine and return the max value of a list of positive numbers. """
print( f"At the beginning of maxValue({values})")
currentMax:int = -1
for value in values:
print( f"value: {value}, currentMax: {currentMax}")
if value > currentMax:
currentMax = values
return currentMax
randomValues:list = []
for i in range(random.randint(0,4)):
randomValues.append( random.randint( 0, 20 ) )
print(f"maxValue({randomValues}) is {maxValue(randomValues)}")
The print statements help us to determine:
Sometimes currentMax holds an int value and sometimes it holds a list
We think it should hold an int, according to how we type-hinted
Always in the first iteration it holds an int
In the second iteration, it sometimes holds a list
The bug is:
In the conditional within the loop, we accidentally used
currentMax = values
and should have used
currentMax = value
A single s can produce a really hard-to-find bug!
Next: Debugger tool