APL SURP Python course - Notebook 1 (completed version)#
Introduction to Python, variables, lists, 1-D arrays, and debugging#
Created for the University of Washington Applied Physics Laboratory’s Summer Undergraduate Research Program (SURP) 2025.
For additional resources on Python basics, you can consult the following resources on the APL-SURP Python course website:
Tutorials on Python fundamentals: https://uw-apl-surp.github.io/aplsurp-python/overview.html
Complementary lessons on specific Python topics: https://uw-apl-surp.github.io/aplsurp-python/complementary_lessons.html
Part 1: Python and notebooks#
Computer code allows us to work with data, create visualizations, and create repeatable scientific workflows. It is an integral part of the modern scientific method!
Every programming language has a specific syntax. In English as well as programming languages, syntax describes valid combinations of symbols and words:
Syntactically invalid: “boy dog cat”
Syntactically valid: “boy hugs cat”
Syntactically valid (but semantically invalid): “cat hugs boy”
Semantics refer to whether a phrase has meaning. It’s up to us to write computer code that has scientific meaning and is useful. The computer will allow us to write code that is syntactically valid but semantically – or scientifically – incorrect!
(Image source: tiobe.com)
As of 2025, Python is likely the most widely-used programming language in the world, and its popularity continues to rise above other languages.
No programming language is perfect. As the inventor of C++ once said, “There are only two kinds of programming languages: the ones people complain about and the ones nobody uses.”
However, there are many reasons that we use Python instead of other programming languages, like MATLAB, Java, or C:
It’s free!
It reads a bit like written English, so it’s easier to write and understand
It’s old, so it’s very stable (Python was created in 1991)
It can do almost anything
It’s incredibly popular inside and outside of science (so it could help you land a job)
It’s open source, which means anyone can help to improve it
For more discussion of why Python is valuable and why its open source origin is important, see the APL-SURP Python course website: https://uw-apl-surp.github.io/aplsurp-python/python.html.
Question: How many of you have heard of Python before this course? Who has written code in Python before? Keeping your hands up, who has written code in any language before?
This web page is called a Jupyter notebook. It lets us write and run computer code, and the results get displayed and saved alongside the code.
In a Jupyter notebook, you can mix and match code cells and text cells. Text cells don’t get interpreted as Python code. You can double-click on a text cell to edit it.
Try creating a new text cell using the menu button (+TEXT), write a message in it, then delete the cell.
Just like in a Google Doc, you can add comments to a cell using the button at the top right of the cell. Try this!
Question: When we run Python code in this notebook, where is the code actually being run?
Google Colab (short for Colaboratory) is an online platform that lets you create and execute Jupyter notebooks from your web browser, like Chrome or Safari. Colab is free to use.
When you create a new Colab notebook, it is stored in your Google Drive account. You can share Colab notebooks just like you would share a Google Doc using the “Share” menu at the top right of the page.
You can download this notebook to your computer using the File menu -> Download. The file extension will be .ipynb
. You can run Jupyter notebooks on your computer (what we would call “running locally”) if you have Python and key packages installed. If you wish to install and run Python locally, the APL-SURP Python course website offers information on doing so: https://uw-apl-surp.github.io/aplsurp-python/install-run.html.
Sometimes it makes more sense to create a Python script instead of a Jupyter notebook. Scripts are plain code files written that run from top to bottom, and they don’t save the output. Their file extension is .py
.
Getting started with coding#
First, we always have to load packages into the notebook using the import
command! Packages contain additional functions that allow us to get more stuff done.
To run a coding cell, you can click the “play” button or type Shift
-Enter
(PC) or Shift
-Return
(Mac) on your keyboard. Try this with the cell below:
import numpy as np # NumPy is an array and math library
import matplotlib.pyplot as plt # Matplotlib is a visualization (plotting) library
import pandas as pd # Pandas lets us work with spreadsheet (.csv) data
from datetime import datetime, timedelta # Datetime helps us work with dates and times
When we write import numpy as np
, we are telling Python: “import the package NumPy and we will access it using the abbreviation np
from here onwards.” You could technically use any abbreviation, but np
is standard for NumPy.
# This is a comment. Nothing happens when this cell is executed!
Often we’d like to add notes to our code. You can do this using Python comments (which are not the same as Google Colab comments).
Python comments are notated using a #
(hash) symbol. Everything after the #
is ignored and not treated like code.
Can you add a Python comment to the code cell above, then execute the cell? What happens?
Part 2: Variables, math, and string formatting#
We can use Python as a calculator. Run the cell below:
3 + 9
12
2 + 5
7
Note that parentheses can be used to change the order of operations:
1 + 2 * 3 + 4
11
(1 + 2) * (3 + 4)
21
If Python doesn’t recognize the code, it will give an error.
Run the code below. What helpful information does the resulting error message include?
# Uncomment the line below to run:
# 3 + hello
Can you figure out how to multiply and divide numbers? Try doing some math yourself below.
10 * 2
20
10 / 2
5.0
Usually, Python needs to be told when to “print” something to the screen. For this, we use the print()
function:
print("Hello world!")
Hello world!
Notice how the function requires a set of parentheses, ( )
, which follow immediately after the name of the function (print
).
Try writing code to print a different message:
print('SURP is amazing!')
SURP is amazing!
Note how comments are used in two ways below, both to describe a section of code and to annotate a specific line:
# This is a section comment
print('This is not a comment')
print('This is also not a comment') # This is a line comment
This is not a comment
This is also not a comment
In Python, we use variables to store information. Variables can be numbers (integers or floats), combinations of characters (called strings), a boolean (which are either True or False), or other variables that are generally called “objects”.
To save (or “assign”) a variable, we use the equal sign (=
). You can name your variable anything descriptive, as long as it’s one word! Note that underscore (_
) can be used to join words in a variable name.
a = -5 # This variable is an "integer" because is a whole number (a number without a decimal point)
almost_ten = 9.9 # This variable is a "float" because is a floating point number (a number with a decimal point)
scientific = 2e3 # This variable is also a float, and is written in scientific notation: 2.0 x 10^3 = 2000
topic = 'OCEAN' # This variable is called a string
topic_2 = "ATMOSPHERE" # You can also specify strings using double quotation marks
this_is_a_boolean = True # This variable is a boolean
print(a)
-5
print(almost_ten)
9.9
print(scientific)
2000.0
print(topic)
print(topic_2)
OCEAN
ATMOSPHERE
print(this_is_a_boolean)
True
You can do math or other operations on the same line where you create a variable!
result = 2025 - 1915
print(result)
110
You can also change a variable using this compact notation:
a += b
is the same asa = a + b
a -= b
is the same asa = a - b
a *= b
is the same asa = a * b
result += 50
print(result)
160
Try the following:
Search on Google for the formula to convert Fahrenheit to Celsius.
Save a variable with the current Seattle temperature in Fahrenheit (feel free to guess, or look it up).
In one line, create a new variable with that temperature converted into Celsius using the math formula.
Print the result!
# Write your code here:
temp = 62 # Fahrenheit
new_temp = (temp - 32) * (5/9) # Celsius
print(new_temp)
16.666666666666668
Note that Python treats booleans (True
and False
) like the integers 1 and 0, respectively. This means you can do math with booleans. What will the code produce below, and why?
print((False * 5) + (True * 3))
3
What happens when you add two strings together? Try it below.
# Write your code here:
print('APL' + ' ' + 'SURP')
APL SURP
You can also create strings that include variables! Here are two ways:
The first way is called an f-string, for “formatted string”. To create one, start the string with the letter f
and embed the variables inside using curly brackets ({...}
):
example_f_str = f'The value of almost_ten is {almost_ten}'
print(example_f_str)
The value of almost_ten is 9.9
The second way is using the .format()
method. Add this to the end of a string. Variables or listed inside the parentheses, separated by commas, can be referred to in order using curly brackets: {0}
, {1}
, {2}
, etc.:
other_example = 'Some SURP interns will study the {0} and the {1}'.format(topic,topic_2)
print(other_example)
Some SURP interns will study the OCEAN and the ATMOSPHERE
Part 3: Lists, 1-D arrays, indexing, and slicing#
To store multiple numbers, we can use lists or NumPy arrays. Lists and arrays are types of variables, and NumPy is one of the packages that we imported at the top of this notebook. Here’s how we create a list or array:
my_list = [1,2,3,4,5]
my_array = np.array([1,2,3,4,5,6,7,8,9])
print(my_list)
print(my_array)
[1, 2, 3, 4, 5]
[1 2 3 4 5 6 7 8 9]
You can add elements to the end of a list by appending. The syntax is:
list_name.append(NEW_ELEMENT)
# Append to the list that you created earlier:
my_list.append(6)
my_list.append(7)
print(my_list)
[1, 2, 3, 4, 5, 6, 7]
You can convert a list to an array by putting it inside np.array()
:
converted = np.array(my_list)
print(converted)
[1 2 3 4 5 6 7]
Here’s a big difference between the two: A list can store a combination of numbers and strings, while an array can store only one variable type (so just numbers, or just strings).
combo_list = ['element #1', 2, 'element #3', 4]
print(combo_list)
['element #1', 2, 'element #3', 4]
Arrays allow us to do math. This is very useful!
Before running the cells below, what do you expect will be the result of each line of code?
my_array + 5
array([ 6, 7, 8, 9, 10, 11, 12, 13, 14])
my_array * 2
array([ 2, 4, 6, 8, 10, 12, 14, 16, 18])
my_array + my_array
array([ 2, 4, 6, 8, 10, 12, 14, 16, 18])
np.array([50,100,150]) + np.array([1,1,1])
array([ 51, 101, 151])
What happens when you add two lists together? Try it!
# Write your code here:
[1,2,3] + [4,5]
[1, 2, 3, 4, 5]
How about when you multiply a list with an integer?
# Write your code here:
var = [1, 2, 3, 4] * 4
print(var)
[1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]
Indexing and slicing#
If we want to retrieve certain elements from a list or array, we need to count the position of the elements, which we call an index. More than one index are indices. In Python, indices start at 0, not 1. For example:
List:
['A', 'B', 'C', 'D', 'E', 'F', 'G']
Indices: A = 0, B = 1, C = 2, D = 3, E = 4, F = 5, G = 6
To extract the element, we can index or slice into the list or array using a bracket [ ] after the variable name:
Indexing:
variable_name[INDEX]
Slicing:
variable_name[START_INDEX:END_INDEX]
Note that when slicing, END
is exclusive, so it is the index after the final element that you want. Also, either START
or END
are optional.
Run each cell below and think about why the results make sense:
year = [2,0,2,5]
print(year)
[2, 0, 2, 5]
# Examples of indexing:
print(year[0])
print(year[3])
print(year[-1]) # This is pretty neat! Negative indexing counts backwards from the end
2
5
5
# Examples of slicing starting from the first element:
print(year[0:4])
print(year[0:])
[2, 0, 2, 5]
[2, 0, 2, 5]
# Examples of slicing to or from the 2nd element (at index #1):
print(year[:1])
print(year[1:])
[2]
[0, 2, 5]
Can you find two different ways to extract the last two elements ([2,5]
) of the variable year
?
Try using one of them to save ([2,5]
) into a new variable.
# Write your code here:
# Option 1:
year = np.array([2,0,2,5])
a = year[-2:]
print(a)
# Option 2:
year = np.array([2,0,2,5])
a = year[2:]
print(a)
[2 5]
[2 5]
Similarly, you can use indexing or slicing to assign new values in specific elements in a list or array:
print(year) # Before modifying last element
year[3] = 9
print(year) # After modifying last element
[2 0 2 5]
[2 0 2 9]
What will array_to_modify
be after the following assignments? Test your prediction by printing the variable below:
array_to_modify = np.array([10,20,30,40,50])
array_to_modify[0] = 0
array_to_modify[1:4] = np.array([21,31,41])
array_to_modify[4] *= 2
# Write your code here:
print(array_to_modify)
[ 0 21 31 41 100]
We can track changes in a variable over time by printing the variable after each change:
array_to_modify = np.array([10,20,30,40,50])
print(array_to_modify)
array_to_modify[0] = 0
print(array_to_modify)
array_to_modify[1:4] = np.array([21,31,41])
print(array_to_modify)
array_to_modify[4] *= 2
print(array_to_modify)
[10 20 30 40 50]
[ 0 20 30 40 50]
[ 0 21 31 41 50]
[ 0 21 31 41 100]
What happens when you index or slice into a string? Try it!
my_string = 'projector'
# Write your code here:
my_string[6:]
'tor'
You can use the function len()
to get the length of a list, array, or string (we’ll talk more about functions later):
print(len(year))
print(len(my_string))
4
9
Part 4: Debugging code#
It is completely normal to make mistakes when writing code. Finding the mistakes is the biggest challenge in programming.
We refer to this process of finding and correcting mistakes, or “bugs”, as debugging.
This flowchart below offers some tips for where to start, depending on whether your code is generating an error or just failing to work silently:
Image source: pythonforbiologists.com
Step 1: Start by reading your code, line by line#
The best way to start debugging is almost always by reading your code carefully line-by-line to understand what is happening. This is known as the “rubber duck method,” and is explained below:
Image source: rubberduckdebugging.com
Step 2: Diagnose errors#
If your code generated an error, read the error. The error will say something like SyntaxError
and will highlight the line of code that produced the error.
The type of error should give you a good clue as to what went wrong. For example, a SyntaxError
means that your code doesn’t follow the correct syntax rules. It might be missing a parenthesis, a quote mark, or some other syntax-related issue.
If you’re not sure what the error means, then copy and paste the error line into Google search.
Step 3: Trace your code using print
statements#
Sometimes it’s hard to tell what your code is doing because you don’t know what certain variables are doing.
A useful debugging technique is to add print()
statements throughout your code to “trace” how variables change as they get assigned and modified.
You saw a demonstration of this technique earlier in the indexing and slicing section:
array_to_modify = np.array([10,20,30,40,50])
print(array_to_modify)
array_to_modify[0] = 0
print(array_to_modify)
array_to_modify[1:4] = np.array([21,31,41])
print(array_to_modify)
array_to_modify[4] *= 2
print(array_to_modify)
[10 20 30 40 50]
[ 0 20 30 40 50]
[ 0 21 31 41 50]
[ 0 21 31 41 100]
Step 4: Consult Google or ChatGPT#
If all else fails and you just can’t figure out what is happening in your code, use Google or ChatGPT.
Google will probably only be helpful if you have an error. But for the most challenging errors, Google is often better than ChatGPT. Usually a search will return useful question-and-answer threads on StackOverflow.com.
ChatGPT can sometimes interpret multiple lines of code, if you ask it to find a bug. But be aware that the solutions that ChatGPT offers may not be correct or efficient.
No matter what solution you find, make sure that you understand how and why the code works before using it in your project.