Unit 1: Programming Basics

Lesson 7: Debugging

Notebook Authors

(fill in your two names here)

Team Roles

Facilitator: (fill in name)
Spokesperson: (fill in name)
Process Analyst: (fill in name)
Quality Control: (fill in name)

If there are only three people in your team, have one person serve as both spokesperson and process analyst for the rest of this activity.

At the end of this Lesson, you will be asked to record how long each Model required for your team. The Facilitator should keep track of time for your team.

Computational Focus:

Model 1: Logical Operators

The if-statement and the while-loop both rely on a condition based on a Boolean expression. The logical operators and and or can be used to combine multiple Boolean expressions to build a condition that evaluates to either True or False. The not operator yields the opposite Boolean value of the original Boolean expression.

Type (don't copy and paste) the following code, one line per Jupyter cell, to observe the output (if any):

a, b, c = 3, 4, 5
print(a<b and b<c)
print(a<b or b<c)    # third line
print(a<b and b>c)   
print(a<b or b>c)    # fifth line
print(not a<b)
print(a>b or not a>c and b>c)

If all three logical operators appear in the same expression, Python will evaluate the not first, then and, and finally or. If there are multiples of the same operators (for example, two and operators), they are evaluated left to right.

Critical Thinking Questions

1. Based on the variable assignments defined in Model 1, what is the value of a < b?

2. If two True Boolean expressions are compared using the logical operator and, what is the resulting Boolean value?

3. Using the variables a, b and c defined in the above model, write an expression below that will compare two False Boolean expressions using the logical operator or (similar to the third and fifth lines of code above).

4. Using expressions similar to the above model and your answer to the previous question, complete the following two tables indicating the resulting Boolean value obtained from comparing two Boolean values (which may correspond to two different Boolean expressions) with the logical operator and and the logical operator or.

and Operator:

p q p and q
True True
True False
False True
False False

or Operator:

p q p or q
True True
True False
False True
False False

6. Examine the last line of Python code from the above model. Consider how Python might evaluate this line of code without actually running the code.
6a. Evaluate the Boolean expression from left to right, ignoring order of precedence. Show your intermediate steps (by copying and pasting this line repeatedly and replacing portions with True and False). You should have at least five lines.

            a>b or not a>c and b>c

6b. Now evaluate the same expression but follow the order of precedence rules explained in the Model. Again, you should show your intermediate steps.

            a>b or not a>c and b>c

7. Assuming a and b still have the values 3 and 4, evaluate the following Boolean expression in the order that Python would evaluate it. Show your work for all four steps:

            not a<10 or b<20

8. Suppose you want to evaluate the logical operators in a different order.

8a. How would your team rewrite the Boolean expression in the previous question so that the or operator is evaluated before the not operator?

8b. What is the value of the entire Boolean expression now?

9. Assume you wanted to execute the statement sum = x + y only when both x and y equal one. Determine the appropriate logical operator, and write a single Boolean expression for this if condition.

10. For the Boolean expression identified in previous question, assume you replace the logical operator with alternate possibility (e.g. and replaced by or). Describe in words the new conditions for which your new Boolean expression is executed.

11. Assume your team needs to execute the statement sum = x + y except when both x and y equal one. Write a Boolean expression for this condition.

12. Now assume you want to repeat the execution of the statement sum = x + y many times as long as x and y do not both equal one.

12a. Begin by creating a Boolean expression for when you want the loop to stop.

12b. A while-loop condition needs a Boolean expression for when you want the loop to repeat (not stop). Modify your Boolean expression from (a) so it can serve as the while-loop condition.

Model 2: Debugging by Printing

At the end of Lesson 3, we learned about the program design process:

  1. Understand the problem.
  2. Design an algorithm to solve the problem. If the problem is large, break the problem into steps.
  3. Write code to solve each step of the problem.
  4. Test your code.
  5. Debug your code.

Testing and debugging (steps 4-5) can often take longer than steps 1-3. To help you learn these skills, this model provides you with a function with many errors in it. Even if one member of your group sees the error, your group should still proceed through the steps to see how to debug this type of error.

The following (broken) function prompts the user for numbers and attempts to sum up numbers until their sum is greater than 10 or less than -10. It returns the average of all the numbers entered.

# broken function - tries to sum up numbers and calculate average 
def model_two():
    total = 0
    count = 0
    value = int(input("Please enter a value: "))
    while total >= -10 or total < 10:
        value = int(input("Please enter another value: "))
        total = total + value
    average = count / total
    return average

print("average is: ", model_two())

Do not try to run or fix this code yet!

Critical Thinking Questions

13. Before you run the program, you should come up with test cases. Each test case would be a series of numbers that would be entered and should include the total and average that SHOULD be calculated.

13a. Explain why four 0's would not be a valid test case for the program described in the above model.

13b. As a group, come up with at least two test cases and put them into the table in the cell below (replacing the first test case).

numbers total average
0,0,0,0 0 0

Helpful hints about interrupting and hiding output in Jupyter

Just like when we hit infinite loops, in these exercises we are going to have some, well, issues and it is helpful to remember a few tricks. I think the keyboard shortcuts are helpful in dealing with nonsense and shenanigans when they occur.

Here are a few reminders of helpful keyboard shortcuts in command mode:
Key : effect
H : show keyboard shortcuts
O : toggle output of selected cells
I,I : interrupt kernel

note: they are all keystrokes, no shift

14. Enter and run the code for model_two() exactly as it is above. Explain the behavior that you see.

15. To see why this behavior is occurring, add a print command to the start of the while loop (as the first line inside the while loop). Print out BOTH total and value to see what is happening. Will the while loop stop when the total is less than -10? Will it stop when the total is greater than 10? Explain.

16. Based on your answer to the previous question, it should be clear that your while loop condition must be incorrect. Fix the error in the loop condition so it stops when the total no longer falls within the range [-10..10]. Describe the error below. For now, do not worry about the total and average being calculated incorrectly. If you cannot fix the looping error within three minutes, ask for help.

17. Now that the loop is stopping correctly, run the program again, using one of the test cases you wrote down earlier. You should notice that the intermediate values for total are incorrect. For now, do not worry about the average being calculated incorrectly (we will fix it in the next model). Fix the function so that the total is calculated correct. Explain your fix here:

18. Review the debugging steps that we have used to debug so far, and describe at least two debugging techniques here:

Model 3: More advanced debugging with nbtutor

In order to do more advanced debugging, we wil use a Jupyter Notebook extension called nbtutor which is based on the cool Python Tutor web-based tool but works in the notebook.

First you'll need to install the package for nbtutor. Since we all installed Anaconda at the beginning of class, the easiest way to do that is with the conda package manager. Type the command below into a Terminal window.

conda install -c conda-forge nbtutor

If your Mac can't find conda, you may need to find where you installed Anaconda and use the full path, for example:
/anaconda/bin/conda install -c conda-forge nbtutor

If your Windows machine can't find conda, you may need to find where you installed Anaconda and use the full path, try (replace helen with your username):
/Users/helen/anaconda install -c conda-forge nbtutor

If you are having trouble with permissions in Windows, then find the command prompt, right click on it and select the 'Run as administrator' option, then try to run the install code again.

Then, you'll have to save and close out all of your notebooks and restart the server application.

Once you think you're ready to go, run the code cell below:


In [ ]:
%load_ext nbtutor

If you get any kind of error message, make sure that you followed the instructions above. If you did everything correctly and still get an error, flag an instructor.

Once you've got everything good to go with nbtutor, check out the demonstration of nbtutor in the animated GIF from the developers below:

As you can see from the (somewhat annoying) animated GIF, nbtutor, and most debuggers, allow you to step through each line of your code and examine the value of all of the variables and how they change as each line of code is executed. As your code gets more complicated it becomes harder and harder to include a print() in every location necessary to debug, so a more formal debugging system (like nbtutor) is helpful.

Notice that when you want to use nbtutor you need to start the cell with:

%%nbtutor

and the function definition and the function call need to be in the same cell.

Critical Thinking Questions

In order to get a sense of how nbtutor can help debug code we will first use it to examine a very simple function. Look at the code in the cell below and fill in the table for the value of i that you would predict at each step. (in this case step 0 means the initial assignment, before the loop, whereas step 1 means at the end of the first loop )

step value of i
0
1
2
etc.

Now run the code in the cell below and step through the code making note of the values of i.


In [ ]:
%%nbtutor
def count(number):
    i = 0
    while i < number:
        i += 1
        print(i)
    return i
count(5)

19. It's also a good idea to examine both memory and timeline modes of nbtutor.
19a. Explain how these two modes differ

19b. How did you do with your predictions? Explain any differences.

19c. Make note of 2 other things that you think would be useful about using nbtutor for debugging.

Copy and paste your current, nearly working version of model_two into the code cell below and run the cell, stepping through the code to try to debug it.


In [ ]:
%%nbtutor
#your model_two() here

20. In the cell above as you use the debugger,
20a. What input values did you type in?

20b. What average did you expect?

20c. What values did you actually see (at the end of the function) for these variables:

variable value reported correct value
average
count
total
value

21. While all the values are incorrect, one of the values is glaringly obviously incorrect. Which one? Fix the function so that variable is calculated correctly. Paste your fixed code in the code cell and describe your fix in the markdown cell below.


In [ ]:

22. Once that variable is calculated correctly, re-examine the printed values of all three variables. This time, concentrate on the average being calculated. Based on the printed value for total and count, the average is being calculated incorrectly. Examine the code after the while-loop, and fix the code so average is being calculated correctly from total and count. Paste your fixed code in the code cell and describe your fix in the markdown cell below.
(use nbtutor and or print() as needed to debug your code and get to a final, working model_two function. Make sure that final, working version is in its own cell)


In [ ]:

23. Examine all the test cases you developed and make sure your function is successful for ALL the test cases. Identify any additional test cases needed to guarantee that your function is correct. For this it is useful to think about the boundary or border cases where you expect something different to happen.

24. Imagine you wrote a largest_of_three function that takes three numbers as its parameters and returns the largest of the three values. List six test cases you might use to check that your function worked correctly. (Each test case would include the three input numbers.)

Temporal Analysis Report

How much time did it require for your team to complete each Model?
Model 1:
Model 2:
Model 3:

END OF CLASS