Ranging from Creation to Debugging

Jed Rembold & Fred Agbo

January 29, 2025

Announcements

  • Feedback on PS1 will be out next week
  • You have Problem Set 2 due on Monday at 10 pm
    • You have everything you need to do all the problems after today
  • Remember to attend your section and also get help from your section leader
  • Use my office hours T, TH, & FR if you want to see me
  • We will be concluding chapter 2&3 of the text today. Hope eveyone is reading the text along
  • Link to Polling https://www.polleverywhere.com/agbofred203

Review Question and Understanding Check

Which of the below blocks of code would print something different from the others?

for n in range(10):
    if n % 2 == 0:
        print(n)
for i in range(0,10,2):
    if i > 0:
        print(i)
for j in '02468':
    L = int(j)
    print(L)
for k in range(0,10):
    if not (k % 2 > 0):
        print(k)

Algorithms

  • Recall that when approaching a computation problem, you must have an algorithm designed before you start coding
  • An algorithm is a problem-solving strategy, and should be:
    • Clear and unambiguous, in the sense that it is understandable and leaves no gaps
    • Effective, in the sense that each step is actually possible
    • Finite, in the sense that it ends at some point
  • You need to come up with an algorithm before you start coding!

Creating your own Algorithms

  • Some useful hints to keep in mind when constructing your own algorithms:
    • Think about how you would solve the problem without a computer. You can’t write code if you don’t understand what you want the computer to do.
    • Computers are fast! Brute force methods are often very viable, or at least a good starting point.
    • Try to use tools and programming patterns you have already seen. It is often far easier to write programs by assembling pieces from code you have already seen than writing each program entirely from scratch.
      • Common patterns we have already seen include: looping over sequences, and using variables to track/control a loop
    • Recognize that the program you write is highly unlikely to work the first time
      • Errors can occasionally be in your algorithms
      • More often, early on, errors are in your translating of the algorithm into Python (the implementation)

Example: Greatest Factor

  • Suppose we wanted to write a function to compute the greatest factor of a provided number (not including the number itself)

  • Algorithm:

    • Brute force – check all smaller values to see if factor
    • Start at top and work down, means first found is the greatest
    • Check if factor by seeing if remainder 0
def greatest_factor(num):
    """Finds the greatest factor of a number."""
    for i in range(num-1,0,-1):
        if num % i == 0:
            return i

Debugging

If debugging is the process of removing software bugs, then programming must be the process of putting them in.

Edsger W. Dijkstra

  • Everyone makes mistakes when writing code
  • A core skill then is in efficiently finding the bugs that you introduce
  • We’ll spend the rest of today looking at some good practices
    • As always though, practice makes perfect

Strategy #1

Concentrate on what your program IS doing, instead of what it SHOULD be doing.

  • It may be impossible to find code that is missing
  • Instead focus on determining what your program is doing, or why it is behaving a certain way
  • Only once you understand what it is currently doing can you entertain thinking about how to change it productively

Strategy #2

Let Python help you: print or log the state of different variables.

  • Many errors are caused by you expecting a variable to have some content that it doesn’t have
  • Get Python to help you by adding print statements to print those variables out
  • Add print statements in blocks of code that you aren’t sure are being accessed to see if you see a message

Strategy #3

Stop and read. The documentation. The error messages.

Parsing Error Messages

  • Start at the bottom! That is where the general type of error and a short description will show up.
  • Want to know where it happened? Look one line up from that.
    • Will show a copy of the line where the error occurred
    • One line up from that will include the line number
  • Want nicer error messages?
    • The rich library offers some very pretty error messages: install with pip install rich

    • At the top of your code, then include:

      from rich.traceback import install
      install(show_locals=True)

Strategy #4

Use PythonTutor or a debugger to track EXACTLY what is happening in your program.

Strategy #5

Don’t make random changes to your code in the hopes that it will miraculously start working.

  • Making random changes is easy, fast, and doesn’t require a lot of thought
  • Unfortunately it is, at best, a wildly inefficient method of debugging, and at worst, actively detrimental
  • If you don’t know what you need to fix yet, you either haven’t:
    • Defined what you are attempting to do clearly enough, or
    • Understood / tracked your program well enough to know what it is currently doing

Strategy #6

Talk it out.

  • Explaining things verbally, in plain English, uncovers a shocking amount of misconceptions or mistakes
  • Find someone to talk at about your programming issues
    • It isn’t even important that they understand how to code, or even can talk back to you (though that might help in some cases)
    • Rubber Duck Debugging is where a software developer explains an issue out loud to an inanimate rubber duck

Strategy #7

Test your code as you go! Either manually or automatically.

  • Know that everyone makes mistakes. The longer you go without testing that something in your program works, the harder it is to find where the mistake eventually is.
  • Write code that you test in small pieces as you go
    • Decomposition into smaller functions is great for this: test each function individually as you go
    • In the projects we try to construct the Milestones for this exact same purpose

Class Activity?

// reveal.js plugins