Debugging and Trouble Shooting
Download
Report
Transcript Debugging and Trouble Shooting
Debugging
CMSC 201
Announcements
Hw2, Hw3 grades returned
if something doesn’t seem right, ask
Midterm next Thurs (Oct 23)
we’ll review on Tues
no hw next week
still have lab
Questions?
Debugging
Debugging is the process of removing errors from our
code.
It, like anything else in computer science, takes practice.
Errors
There are three kinds of errors you’ll run into:
• Syntax errors—These are errors that occur from poorly
formed python syntax.
• Exceptions—Exceptions occur when you try and do
something that python can’t let you do, like access an
element of a list that doesn’t exist.
• Logic Errors—Logic errors occur when your program
terminates successfully, but just doesn’t do the right
thing.
Syntax Errors
These are the easiest kind of error to debug!
1. Look at what python is telling you the problem is.
2. Go to the line python is telling you the problem is on.
3. Fix the part of your program that is incorrect python.
In some cases, you might have to look at your
indentation, or the line above!
Exceptions
Possible reasons for exceptions:
• File not found
• List index out of bounds
• Expected an integer but got a string
Fixing these is also not a big deal!
Python will tell you exactly what the error is, and what line
it happened on. If a quick inspection of that line does not
help you figure out what’s wrong, you might want to move
on to the tricks we talk about for logic errors.
Logic Errors
Logic errors are when your program simply does the
wrong thing. These are the hardest to fix.
Typically, with a logic error, all you know is that your
program is producing incorrect output. The trick is to
isolate where the error is happening.
Why We Have Functions
When we’re trying to hunt down an error, functions are a
helpful tool for this. Because functions take a small
number of arguments and return a value, it’s easy to
isolate them from the rest of the program to see if they’re
working or not.
def someCrazyFunction(input1, input2, input3):
#All sorts of code
return blah
In order to see if our error is in this function, we can
simply run it in main with a variety of different inputs and
verify if it works or not.
How To Test A Function
Imagine we have a sort function. What possible ways can
we test it?
sort([1, 10, 4, 5, 2])
Pretty standard! We know what the output should be.
This is a general test case.
How To Test A Function
Depending on how our program’s using it though, there
could be other, weird cases!
sort([])
sort([2])
These are called edge cases—the program should work,
but it wasn’t necessarily what you had in mind.
How To Test A Function
Notice that we can also have cases like these:
sort([ “hats”, 1])
sort(10)
However, these aren’t really worth testing! They will
always break our sort function, and should! They violate
what’s called the function’s precondition.
Precondtion
A precondition is something that must be true about a
function’s inputs in order for it to do its job.
For sort(), an example would be “It must get a list of
things that can all be compared to each other.”
For a square root function, the precondition could be
“Input must be a positive number.”
Preconditions should be described in the function header
comment.
Testing Functions
So for functions, we want to test several general cases
and several edge cases, and make sure that if something
violates it’s precondition it reacts appropriately.
Once a function has been thoroughly tested, you know
that function’s not going to be a problem anymore!
Finding Errors
Eventually, you’ll get to a function that is not producing the
correct output, and your new job is to isolate the error
within that function.
Example
def longestSubSeq(myList):
lastItem = myList[0]
current = 0
best = 0
for item in myList:
if(item == lastItem):
best = best + 1
if best < current:
best = current
else:
lastItem = item
current = 1
return best
What are some good test cases?
Test Cases
def main():
print(longestSubSeq([1])
print(longestSubSeq([1, 2,
print(longestSubSeq([1, 1,
print(longestSubSeq([1, 1,
print(longestSubSeq([1, 1,
3])
1, 2])
2, 1])
2, 3, 2, 2, 2, 2])
Each of these targets a different place where something could go
wrong!
Test Cases
def main():
print(longestSubSeq([1])
print(longestSubSeq([1, 2,
print(longestSubSeq([1, 1,
print(longestSubSeq([1, 1,
print(longestSubSeq([1, 1,
Output:
File "oct14.py", line 17
print(longestSubSeq([1, 2, 3])
^
SyntaxError: invalid syntax
3])
1, 2])
2, 1])
2, 3, 2, 2, 2, 2])
Test Cases
def main():
print(longestSubSeq([1]))
print(longestSubSeq([1, 2,
print(longestSubSeq([1, 1,
print(longestSubSeq([1, 1,
print(longestSubSeq([1, 1,
Output:
1
1
3
2
5
3]))
1, 2]))
2, 1]))
2, 3, 2, 2, 2, 2]))
Test Cases
We know something’s wrong! How do we find it?
Strategies
Tracing by hand can be effective. Take the input, pretend to be
the computer, and try and run the program yourself.
Pros:
Gives you a good idea of what your program is doing.
Can help find simple errors.
Cons:
Can take awhile, especially for things with loops.
Can be impractical for large inputs.
Strategies
Print statements.
Pros:
Very informative, you can target specific variables to
print.
Cons:
Have to know what to look at.
Need careful labeling, or they get very confusing.
Example
http://www.csee.umbc.edu/courses/201/fall14/debuggi
ng.py
def longestSubSeq(myList):
lastItem = myList[0]
current = 0
best = 0
for item in myList:
if(item == lastItem):
best = best + 1
if best < current:
best = current
else:
lastItem = item
current = 1
return best
Where are some good places for print statements?
WRONG
def longestSubSeq(myList):
lastItem = myList[0]
current = 0
best = 0
for item in myList:
print(item)
if(item == lastItem):
print(“hello”)
best = best + 1
if best < current:
best = current
print(“here”)
else:
lastItem = item
current = 1
print(“doing thing”)
return best
Example
def longestSubSeq(myList):
lastItem = myList[0]
current = 0
best = 0
for item in myList:
print(“The current item is: “ + str(item)
if(item == lastItem):
print(“Item is part of sequence”)
best = best + 1
if best < current:
best = current
print(“Longest sequence so far”)
else:
lastItem = item
current = 1
print(“Sequence broken”)
return best
Example
Looking at the output, we can see right away that we never make it to
longest sequence so far!
That means best is never less than current…
Looks like we forgot to increment current!
Example
Still doesn’t fix it. Let’s try printing more stuff…
def longestSubSeq(myList):
lastItem = myList[0]
current = 0
best = 0
for item in myList:
print(“The current item is: “ + str(item))
if(item == lastItem):
print(“Item is part of sequence”)
print(“Best is “ + str(best))
best = best + 1
current = current + 1
if best < current:
best = current
print(“Longest sequence so far”)
else:
lastItem = item
current = 1
print(“Sequence broken”)
return best
Example
Still doesn’t fix it. Let’s try printing more stuff…
def longestSubSeq(myList):
lastItem = myList[0]
current = 0
best = 0
for item in myList:
print(“The current item is: “ + str(item))
if(item == lastItem):
print(“Item is part of sequence”)
print(“Best is “ + str(best))
best = best + 1
current = current + 1
if best < current:
best = current
print(“Longest sequence so far”)
else:
lastItem = item
current = 1
print(“Sequence broken”)
return best
Example
def main():
print(longestSubSeq([1]))
print(longestSubSeq([1, 2,
print(longestSubSeq([1, 1,
print(longestSubSeq([1, 1,
print(longestSubSeq([1, 1,
Output:
1
1
3
2
4
3]))
1, 2]))
2, 1]))
2, 3, 2, 2, 2, 2]))
Example
Debugging poorly will be your single biggest time
sink in this class!
Isolate the bug to a function or block of code, and
put in well designed print statements at the start and
end of the broken section, and narrow it down.
Exercise
http://www.csee.umbc.edu/courses/201/fall14/debugging2.py
# Merges two sorted lists.
# Precondition: list1 and list2 are lists of integers already sorted in ascending
# order (smallest to largest)
def merge(list1, list2):
current1 = 0
current2 = 0
result = []
while current1 < len(list1) and current2 < len(list2):
if(current1 == len(list1)):
result.append(list2[current2])
current2 = current2 + 1
elif(current2 == len(list2)):
result.append(list2[current1])
current1 = current1 + 1
elif(list1[current1] < list2[current2]):
result.append(list2[current2])
current2 = current2 + 1
else:
result.append(list1[current1])
current1 = current1 + 1
return result
Exercise
http://www.csee.umbc.edu/courses/201/fall14/debugging2.py
def main():
main()
Write some test cases, and then try debugging!