15  Debugging Your Code

15.1 Some steps to try when you encounter an error

Bugs in your code can be frustrating! But there are concrete steps you can take:

15.1.1 Step 1: Define the Problem.

Think about what you were trying to do vs. what happened instead. Create a hypothesis for what went wrong.

15.1.2 Step 2: Read the Error Message.

Look for a line number where the error is occurring.

Sometimes the bug is in the line before the one that threw the error!

See Section 15.3 below for more.

15.1.3 Step 3: Re-run code from the beginning.

Remember that code is run in order, from the first line in your script to the last one. And specific parts of your code, like for loops or functions, have specific indented contexts. If any of your code is out of order or indented improperly, the rest of the code may not work.

This can happen a lot in JupyterHub, since sometimes you re-run a lower cell without fixing one that’s higher up in your code. Go back to the beginning of your code and re-run to see if that will fix it, and if not go cell-by-cell through the code to find the problem.

15.1.4 Step 4: Talk it out!

Try your best to explain the problem out loud, preferably to a friend or teammate.

Practice rubber duck debugging.

15.1.5 Step 5: Check instructions, documentation, and Google.

If you’re lost, refer to all the resources you have: cheatsheets, guides, online documentation. Don’t forget RAD CAT!

And when in doubt: Google the error message and see if someone else had the same problem!

15.1.6 Step 6: Ask for help!

Don’t let a single bug frustrate you for too long. If none of the above strategies worked, ask a classmate, PAL tutor, or instructor for help with the problem.

15.2 Avoid Bugs before they happen!

15.2.1 Save and/or “Restart and Run All” Often.

If you’re getting the same bug repeatedly in the same cell despite making changes, it could be that something is “stuck” in memory. Use the “restart and run all” button to try it again with a fresh kernel.

15.2.2 Use good names.

Name your variables and dataframes with care. Rename things to make them more clear. Good names can help you find a problem quickly.

15.2.3 Start simple, and build up little by little.

Don’t try to write a whole program all in one go.

15.2.4 Run your code line-by-line.

Check that it works as you go.

15.2.5 Leave yourself good annotations and comments!

Use # to leave comments: remind yourself what certain lines of code are doing.

15.3 Anatomy of an Error Message

Here’s an example of an error message from Pandas:

# Import library
import pandas as pd

# Read in data
penguins = pd.read_csv("../data/penguins.csv")

# Filter only Adelie penguins
penguins_filter = penguins[penguins.Species == "Adelie"]
penguins_filter
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/var/folders/xk/29clchk51j5bm56kqn4v8dsc0000gq/T/ipykernel_45295/490271837.py in ?()
      4 # Read in data
      5 penguins = pd.read_csv("../data/penguins.csv")
      6 
      7 # Filter only Adelie penguins
----> 8 penguins_filter = penguins[penguins.Species == "Adelie"]
      9 penguins_filter

~/CIS241/.venv/lib/python3.12/site-packages/pandas/core/generic.py in ?(self, name)
   6314             and name not in self._accessors
   6315             and self._info_axis._can_hold_identifiers_and_holds_name(name)
   6316         ):
   6317             return self[name]
-> 6318         return object.__getattribute__(self, name)

AttributeError: 'DataFrame' object has no attribute 'Species'

This code uses a lot of best practices (clear variable names, good comments, etc.), but it still has an error. Let’s see if you can decode it.

The bottom line of the error message defines the error itself. Make sure you always scroll to the bottom of the error message first!

In this case the last line says AttributeError: 'DataFrame' object has no attribute 'Species'. Before the colon is the type of error (an attribute error in Pandas refers to a column or attribute of the data), and after the colon Python attempts to tell you what’s wrong (in this case it says that the dataframe doesn’t have a column called “Species”).

Everything above the bottom line of the error message is part of the Traceback, which shows you step by step what went wrong with the code. Sometimes these tracebacks can be very long, but usually you only need a small part of it.

After you’ve looked at the last line, go back to the top part of the Traceback. This will show you the code that you wrote. In our case it looks like this:

<ipython-input-3-ff22716e7d6d> in ?()
      4 # Read in data
      5 penguins = pd.read_csv("../data/penguins.csv")
      6 
      7 # Filter only Adelie penguins
----> 8 penguins_filter = penguins[penguins.Species == "Adelie"]

The Traceback has an arrow that points directly at the line causing the problem. In this case, that’s line 8, the final line of our cell. Sometimes the Traceback will even highlight the part of the line that’s causing the problem!

There’s no highlight here, but the error definition told us what was wrong: the “Species” column. Let’s look at the columns in this DataFrame to see if we can spot the issue:

penguins.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 344 entries, 0 to 343
Data columns (total 7 columns):
 #   Column             Non-Null Count  Dtype  
---  ------             --------------  -----  
 0   species            344 non-null    object 
 1   island             344 non-null    object 
 2   bill_length_mm     342 non-null    float64
 3   bill_depth_mm      342 non-null    float64
 4   flipper_length_mm  342 non-null    float64
 5   body_mass_g        342 non-null    float64
 6   sex                333 non-null    object 
dtypes: float64(4), object(3)
memory usage: 18.9+ KB

Do you see it?

Yes! The column isn’t called “Species”, it’s called “species”. The code accidentally capitalized the word! This is a very easy fix. You can repair the cell like so:

# Import library
import pandas as pd

# Read in data
penguins = pd.read_csv("../data/penguins.csv")

# Filter only Adelie penguins
penguins_filter = penguins[penguins.species == "Adelie"]
penguins_filter
species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g sex
0 Adelie Torgersen 39.1 18.7 181.0 3750.0 Male
1 Adelie Torgersen 39.5 17.4 186.0 3800.0 Female
2 Adelie Torgersen 40.3 18.0 195.0 3250.0 Female
3 Adelie Torgersen NaN NaN NaN NaN NaN
4 Adelie Torgersen 36.7 19.3 193.0 3450.0 Female
... ... ... ... ... ... ... ...
147 Adelie Dream 36.6 18.4 184.0 3475.0 Female
148 Adelie Dream 36.0 17.8 195.0 3450.0 Female
149 Adelie Dream 37.8 18.1 193.0 3750.0 Male
150 Adelie Dream 36.0 17.1 187.0 3700.0 Female
151 Adelie Dream 41.5 18.5 201.0 4000.0 Male

152 rows × 7 columns

And goodbye error message!

Over time, you’ll get used to reading and decoding these error messages on your own, but don’t be afraid to ask questions if you run into one you’re unsure about.