Appendix C — Python tutorial#

Click the binder button Binder or this link bit.ly/pytut3 to run this notebooks interactively.

Introduction#

Python as a fancy calculator#

In this tutorial, I’ll show you the basics of the Python programming language. Don’t worry, learning Python is not complicated. You’re not going to become a programmer or anything like that, you’re just learning to use Python as a calculator.

Calculator analogy. Python commands are similar to the commands you give to a calculator. The same way a calculator has different buttons for the various arithmetic operations, the Python language has a number of commands you can “run” or “execute.” Python is more powerful than a calculator because you can input multiple lines of commands all at once.

Why learn Python?#

Here are some things you can do using Python:

  • Python is a very powerful “basic” calculator that allows you to compute arithmetic expression involving math operations like +, -, *, /, and other math functions.

  • Python is a useful graphical calculator: you can plot functions and visualize data.

  • Python is an extensible, programmable calculator that allows you to define new functions and operations.

  • Python gives you access to extension modules for numerical computing (numpy), scientific computing (scipy), and symbolic math calculations (sympy).

  • Python provides functions for data management (pandas), data visualization (seaborn), and statistics (statsmodels).

If any of these seems useful to you, then read on to get started learning Python!

Getting started#

Installing JupyterLab Desktop#

JupyterLab is a computing platform that makes it easy to run Python code in your browser. JupyterLab provides a notebook interface that allows you run and edit Python commands interactively, which makes it the perfect tool for learning Python.

JupyterLab Desktop is a convenient all-in-one application that you can install on your computer to run JupyterLab. You can download JupyterLab Desktop from the following page on GitHub: https://github.com/jupyterlab/jupyterlab-desktop. Choose the download link for your operating system and complete the install installation. After you launch the JupyterLab application, you should see a launcher window similar to the one shown below.

The JupyterLab interface with the File browser shown in the left sidebar. The box (1) indicates the current working directory. The box (2) shows the list of files in the current directory. Use the Python 3 (ipykernel) button (3) to create a new Python 3 notebook.

Notebooks are interactive documents#

A Jupyter notebook consists of a sequence of cells, similar to how a text document consists of a series of paragraphs. The notebook you created has a single empty code cell, which is ready to accept Python commands. Type in the expression 2 + 3 into the cell, then press SHIFT+ENTER to run the code. You should see the result of the calculation displayed on a new line immediately below your input. The cursor will automatically move to a new code cell, as shown in the screenshot below.

Box (1) shows a code cell and its output. The cursor is currently in the cell highlighted in box (2). The label (3) tells us the notebook filename is Untitled.ipynb. The buttons in box (4) control the notebook execution: run, stop, restart, and run all. The play button executes the code in the current cell, and is equivalent to pressing SHIFT+ENTER. The stop and restart buttons can be used to interrupt a computation that is stuck or taking too long. The run all button is useful when you want to rerun all the cells in the notebook from top to bottom.

Code cells contain Python commands#

The Python command prompt is where you enter Python commands. Each code cell in a notebook is a command prompt that allows you to enter Python commands and “run” them by pressing SHIFT+ENTER, or by clicking the play button in the toolbar.

Let’s see the example commands from screenshot again. We can make Python compute the sum of two numbers by entering 2+3 in a code cell, then pressing SHIFT+ENTER.

2 + 3
5

When you run a code cell, you’re telling the computer to evaluate the Python commands it contains. Python then displays the result of the computation immediately below. In the above example, the input is the expression 2 + 3, and the output is the number 5.

Let’s now compute a more complicated math expression \((1+4)^2 - 3\), which is equivalent to the following Python expression:

(1+4)**2 - 3
22

Note the Python syntax for math operations is similar to the notation we use in math: addition is +, subtraction is -, multiplication is *, division is /, and we use the parentheses ( and ) to tell Python to compute 1+4 first. The syntax for exponents is a little unusual: we use two multiplication signs (asterisks): \(a^n\) = a**n.

Running a code cell is similar to using the EQUALS button on a calculator: whatever math expression you entered, the calculator will compute its value and display its result. The interaction with the Python interpreter is similar: you input some Python code (which can be written on multiple lines), then the computer runs your code and displays the result of the final calculation on the screen.

Your turn to try this!#

Try typing in an expression involving numbers and operations in the following cell, then run it by pressing SHIFT+ENTER or by using the play button in the toolbar.

This remainder of this tutorial notebook contains many code cells pre-filled with examples of Python commands for you to run. You also edit the contents of any code cell, and re-run the code to see how the output changes. I encourage you to play with the code examples interactivity, because this is an excellent way to learn. Use the cell edit buttons (top-right corner in each cell) to duplicate the current cell, or insert a new blank cell at any point in the notebook.

cell operations

Expressions and variables#

Using Python involves computing Python expressions and manipulating data stored in variables. Let’s see some of that.

Expressions#

A Python expression is an arbitrary combination of values, operators, and functions. We write expressions and ask Python to compute their value. Here is an example of an expression involving several math operations, like the ones we saw earlier.

5**2 - 3*(1+7) + 12/6 
3.0

Let’s now look at an example that shows other aspects of the Python syntax that you haven’t seen before: lists and function calls. Here is an expression that computes the sum of a list of three numbers using the function sum.

sum([1, 2, 3])
6

In Python, we define lists using the square brackets syntax [ <elements> ]. The code [1,2,3] defines a list of three elements: 1, 2, and 3. The function sum computes the sum of the list of numbers. The brackets ( <inputs> ) are used to specify the inputs to the function.

We’ll have a lot more to say about lists and functions later on. For now, I just wanted you to see an expression that contains a list and a function to show that expressions can be more than arithmetic operations.

Python comments#

Comments are annotations in code cell intended for human readers. We write comments in Python by prefixing them with the character #. Python will ignore the the # character and any text that comes after it.

# this is a comment

The text # this is a comment is ignored by the Python interpreter. As far as Python is concerned, the above code cell is completely empty. I will use comments throughout the remainder of this tutorial to provide additional explanations about each line of code.

Variables#

A variable is a name we use to refer to some value. This is similar to how variables are used in math: to represent constants, function inputs, function outputs, and all intermediate values in calculations. We use the assignment operator = to store values into variables, which we’ll explain next.

The assignment operator =#

In all the code examples above, we computed various Python expressions, but we didn’t do anything with the results. The more common pattern in Python, is to store the result of an expression into a variable.

For example, here is the code that computes the expression 2+3 and stored the result in a variable named x.

x = 2+3

The result of this expression is that the value 5 gets saved in the variable x. The order in which Python evaluates this expression is right-to-left: Python first sees the expression 2+3 and computes its result 5, then it sees the remainder of the statement x =, which tells it to store the result 5 into the variable x. The assignment statement doesn’t have any output, so this code cell doesn’t display anything.

The meaning of assignment operator = is not the same as the meaning of the operator \(=\) used for writing math equations. The assignment statement x = 5 is a very specific type of equation, where we put the value 5 (the right-hand side) into the variable x (the left-hand side). It is true that after this statement x will be equal to 5, but this is not the most useful way talk about this assignment statement.

Here are some other, more useful ways to describe the assignment statement x = 5:

  • Set x to 5.

  • Put 5 into x.

  • Record 5 under the name x.

  • Define x to be equal to 5.

  • Store the value 5 into the variable x.

  • Save the value 5 into the memory location named x.

In each of these, it is clear that = has the role of an active verb: to store the result of an expression into a particular variable.

To display the contents of the variable x, we can write its name in a code cell.

x
5

Note the variable x, which we defined in the previous code cell, is available in this cell. This is a defining feature of the computational notebook environment: every code cell runs in a “context” that includes the results from all the previous code cells.

Note also we didn’t need to call any special function to display the contents of the variable. This is because, in a notebook interface, the value of the last expression in each code block gets displayed automatically. Later in the tutorial, we’ll learn about the function print that you can use to display values in the middle of a code cell or to customize how values are displayed.

We can combine the commands “assign the result of 2+3 to x” and “display x” into a single code cell, as shown below.

x = 2+3  # store 2+3 into x
x        # print x
5

The first line in this code block computes the expression 2+3 and assigns the result to the variable x. The second line evaluates the variable x to display its contents.

Exercise 1: Imitate the above code block, to create another variable y that contains the value of the expression \((1+4)^2 - 3\), then display the contents of the variable y.

# put your answer in this code cell

Click for solution.

So to summarize, the syntax of an assignment statement is as follows:

<place> = <some expression>

The assignment operator (=) is used to store the value of the expression <some expression> into the memory location <place>, which is usually a variable name. Later in this tutorial, we’ll learn how to store values in other places (inside containers like lists and dictionaries).

Multi-line expressions#

Let’s use what we have learned about Python variables and expressions to perform some real-world calculations.

Example 1: Number of seconds in one week#

Let’s say you need to calculate how many seconds there are in one week. We can do this using multi-step Python calculation, based on the following facts: there are \(60\) seconds in one minute, \(60\) minutes in one hour, \(24\) hours in one day, and \(7\) days in one week.

Rather than trying to compute the answer in a single step, we can use several intermediate variables with descriptive names to help us perform the calculation step by step:

secs_in_1min = 60
secs_in_1hour = secs_in_1min * 60
secs_in_1day = secs_in_1hour * 24
secs_in_1week = secs_in_1day * 7
secs_in_1week
604800

Note we can use the underscore _ as part of variable names. This is a common pattern for variable names in Python code, because the name some_name is easier to read than somename.

Exercise 2: Johnny weights 107 kg, and wants to know his weight in pounds. One kilogram is equivalent to 2.2 lbs. Write the Python expression that computes Johnny’s weight in pounds.

weight_in_kg = 107  # store 107 into weight_in_kg
weight_in_lb = ...  # replace ... with your answer

Click for solution.

Exercise 3: You’re buying something that costs 57.00 dollars, and the government imposes a 10% tax on your purchase. Calculate the total you’ll have to pay, including the 10% tax.

cost = 57.0
taxes = ...   # replace ... with your answer
total = ...   # replace ... with your answer

Click for solution.

Exercise 4: The formula for converting temperatures from Celsius to Fahrenheit is \(F = \tfrac{9}{5} \cdot C + 32\). Given the variable C that contains the current temperature in Celsius, write the expression that calculates the current temperature in Fahrenheit and store the answer in a new variable named F.

C = 20
F = ... # replace ... with your answer

Check your formula works by changing the value of C. When C = 100, the variable F should be 212.

Click for solution.

Variable types#

Every variable in Python has a type, which tells you what kind of data it contains, and what kind of operations you can do with it. For example, there

There are two types for storing numbers, and other types for storing text and binary data. There are also several types of container variables that store other variables.

Here are the most common types of variables in Python:

  • Integers (int): used to store whole numbers like 42,65, 78, -4, -200, etc. Python integers are roughly equivalent to math set of integers \(\mathbb{Z}\).

  • Floating point numbers (float): used to store decimals like 4.6,78.5, 1000.0 = 1e3, 0.001 = 1e-3, 123.456 = 1.23456e2, etc.

  • Lists (list): ordered container for other values. For example, the list [61, 79, 98, 72] contains four integers. The beginning and the end of the list are denoted by the square brackets [ and ], and its elements are separated by commas.

  • Strings (str): used to store text content like "Hello", "Hello everyone". Strings are denoted using either double quotes "Hi" or single quotes 'Hi'.

  • Boolean values (bool): logic variables with only two possible values, True and False.

Let’s look at some examples of the different types of variables:

score = 98                  # an int
average = 77.5              # a float
scores = [61, 79, 98, 72]   # a list
message = "Hello everyone"  # a string
above_the_average = True    # a boolean

Recall, when we want to display the contents of a variable, we write its name as the last line in a code cell. Let’s see the contents of the score variable:

score
98

To see the type of a variable, we can use the function type as follows:

type(score)
int

In this case, the variable score is of type int (integer).

Exercise 5: Display the contents and the type of the variables average, scores, message, and above_the_average that we defined above.

# put your answer here

Click for solution.

Technical jargon: objects and their methods#

Every value in a Python program is an object. The function type tells you what kind of object it is. The term object is programming jargon used to describe the fundamental building blocks used to store data that also have certain functions “attached” to them, which are called methods. For example, every string object has a method .upper() that converts the string to uppercase (capital letters); calling "Hello".upper() produces "HELLO".

The integers, floating point numbers, lists, strings, and boolean values are examples of different types of objects. Different object types have different affordances (what you can do with them). For example, we can subtract numbers, but we can’t subtract strings. Other types of objects that are often used in Python include dictionaries, tuples, sets, functions, etc. We’ll encounter some of these objects later in this tutorial, and talk more about objects and their methods as needed. The key point is that Python objects types are the different kinds of LEGOs available for you to play with, and remember that you can use the function type to find out what kind of object you’re working with.

Functions#

Functions are essential building blocks in programming, since they allow us to encapsulate any sequence of operations as a reusable piece of functionality. You can think of functions as chunks of code that are defined once, and used multiple times by “calling” them from other places in the code.

Calling functions#

The Python syntax for using the function fun on the input <arg> is the function name followed by the input in parentheses: fun(<arg>). In programming, function inputs are called arguments. We can describe fun(<arg>) as calling the function fun with argument <arg>. Other synonyms for calling a function are invoking, evaluating, or running the function. The parentheses notation for calling functions is borrowed from mathematics, where \(f(x)\) (read “\(f\) of \(x\)”) denotes the output of the function \(f\) when the input is \(x\).

Python built-in functions#

Python is a useful calculator because of the numerous functions it comes with, which are like different calculator buttons you can press to perform computations. Here is a short list of the most common Python functions:

  • type(obj): tells us the type of the object obj

  • sum(mylist): calculate the sum of the values in the list mylist

  • print(obj1, obj2, ...): print the text representations of obj1, obj2, etc. separated by spaces

  • len(obj): returns the length of the container object obj

  • help(thing): display help info about the object obj

  • range(a,b): creates a list of numbers [a,a+1,...,b-1]

  • str(obj): converts the object obj to a text (str) representation

We’ve already seen the functions sum and type in earlier code cells, and learn to use the other functions in later sections of this tutorial.

Some functions can accept multiple arguments, and we use commas to separate these arguments: fun(arg1, arg2). For example, we can call the function print with multiple arguments in order to print them together on a single line.

print("average", average)
average 77.5

Some functions accept optional keyword arguments (options) that modify the function’s behaviour. For example, the print function accepts the keyword argument sep (separator) that controls what text is used to separate the different arguments. The default value for sep is a single space " ". If we specify a different value for the sep keyword argument, then the function will use that value as the separator, as shown below.

print("average", average, sep=" = ")
average = 77.5

Python syntax for defining new functions#

Python makes it easy to define new functions, which is like adding new buttons to the calculator. A Python function takes certain variable(s) as input and produces a certain variable(s) as output. We can define a new function called fun using the following syntax:

def fun(<arg>):
    <calculation step 1>
    <calculation step 2>
    return <output>

Let’s go over the code line-by-line and explain all the new elements of syntax. We start with the Python keyword def, then give the name of the function, which is fun in this case. Next, we specify the function arguments the function expects inside parentheses. In this example, the function fun takes a single input called <arg>. The colon : indicates the beginning of the function body. The function body is an indented code block that specifies the calculations that the function is supposed to perform. The last line in the function body is a return statement that tells us the output of the function.

Example 2#

Let’s write a simple function named double, which expects a single number as input, and produces as output the number multiplied by two.

def double(x):
    y = 2*x
    return y

Note the body of the function is indented by four spaces. In Python, we use indentation to delimit when a code block starts and when it ends. This function’s body contains two lines of code, but in general, Python functions can contain dozens or even hundreds of lines of code.

To call the function double, we use the function name followed by the function’s input argument in parentheses, as we saw earlier.

double(6)
12

When Python sees the expression double(6) it recognizes it as a function call. It then looks for the definition of the function double and finds the def statement in the previous code cell, which tells us what steps need to be performed on the input. Visit the link tinyurl.com/bdzr69s9 to see a visualization of what happens when we call the function double with different inputs.

Example 3#

Let’s add a function that adds 10% tax to a given purchase cost and returns the total of cost plus taxes.

def add_taxes(cost):
    taxes = 0.10 * cost
    total = cost + taxes
    return total
add_taxes(57)
62.7

Example 4#

The math formula for computing the mean (average value) of a list of numbers \([x_1, x_2, \ldots, x_n]\) is: \(\overline{\mathbf{x}} = \left( x_1 + x_2 + \cdots + x_n \right) / n\). In words, the average value of a list of values is the sum of the values divided by the length of the list. Let’s write the function mean that computes the mean of a list of numbers.

def mean(values):
    avg = sum(values) / len(values)
    return avg
mean([1,2,3,4])
2.5

Exercise 6#

Write a Python function called temp_C_to_F that converts temperatures from Celsius C to Fahrenheit F. The formula for converting a temperature from Celsius to temperature in Fahrenheit is \(F = \tfrac{9}{5} \cdot C + 32\).

Hint: You can reuse your code from Exercise 4.

def temp_C_to_F(C):
    ...  # replace ... with your code

Click for solution.

In summary, you can think of the def keyword as way to add buttons to the Python calculator.

Lists and for-loops#

Python allows us to easily manipulate data structures that contain thousands or millions of values. For example, a list is an ordered container for values that can be as large as the amount of memory you have in your computer. A for-loop is a programming concept that allows us to repeat some operation multiple times. We often combine lists and for-loops to perform calculations for each element in the list.

Lists#

The Python syntax for creating a list starts with an opening square bracket [, followed by the list elements separated by commas ,, and ends with a closing bracket ]. For example, here is the code to define the list scores that contains four integers.

scores = [61, 79, 98, 72]
scores
[61, 79, 98, 72]

A list has a length, which you can obtain by calling the function len.

len(scores)
4

We use the in operator to check if a list contains a certain element.

98 in scores
True

Accessing elements of a list#

We access the individual elements within the list scores using the square brackets syntax scores[<idx>], where <idx> is the 0-based index of the element we want to access. The first element of the list has index 0, the second element has index 1, and so on. The last element has an index equal to the length of the list minus one.

# first element in the list scores
scores[0]
61
# second element in the list scores
scores[1]
79
# last element in the list scores
scores[3]
72

Note the square brackets syntax is used in two completely different ways: to define lists and to access their elements.

List slicing#

We can extract a subset of a list using the “slice” syntax a:b, which corresponds to the range of indices a, a+1, …, b-1. For example, if we want to extract the first three elements in the list scores, we can use the slice 0:3, which is equivalent to the indices 0, 1, and 2.

scores[0:3]
[61, 79, 98]

Note the result of selecting a slice from a list is another list.

List methods#

List objects can be modified using their methods: .sort(), .append(), .pop(), and .reverse(). Let’s look at some examples of these methods in action.

To sort the list of scores, you can call its .sort() method:

scores.sort()
scores
[61, 72, 79, 98]

To add a new element el to the list (at the end), use the method .append(el):

scores.append(22)
scores
[61, 72, 79, 98, 22]

The method .pop() extracts the last element of the list:

scores.pop()
22

You can think of .pop() as the “undo method” of the append operation.

To reverse the order of elements in the list, call its .reverse() method:

scores.reverse()
scores
[98, 79, 72, 61]

Other useful list methods include .insert(index,newel) and .remove(el), which allow us to insert or remove elements at arbitrary places in the list.

For loops#

The for-loop is a programming concept that allows us to repeat some operation or calculation multiple times. The most common use case of a for-loop is to perform some calculation for each element in a list.

The syntax of a Python for-loop looks like this:

for <element> in <container>:
    <operation 1 using `element`>
    <operation 2 using `element`>
    <operation 3 using `element`>

This above code repeats operation 1, 2, and 3 for each element <element> in the list <container>. The operations we want to repeat are indented by four spaces, which indicates they are part of the body of the for loop. Recall we previously used indentation to delimit the function body.

Example 5: Print all the scores#

We start with a basic example of a for-loop that simply prints the value of each element.

scores = [61, 79, 98, 72]

for score in scores:
    print(score)
61
79
98
72

A for-loop describes a certain action or actions that you want Python to repeat. The for-loop shown in the code cell above instructs Python to repeat the action print(score) for four times, once for each score in the list scores. We know this is the operation to be repeated because it is indented and hence “inside” the for loop.

Example 6: Compute the average score#

The math formula for computing the mean (average value) of a list of numbers \([x_1, x_2, \ldots, x_n]\) is: \(\overline{\mathbf{x}} = \left( x_1 + x_2 + \cdots + x_n \right) / n\). We previously computed the average using the functions sum and len: avg = sum(grades)/len(grades), but suppose we don’t have access to the function sum for some reason, and we want to compute the sum of the grades using a for-loop.

total = 0
for score in scores:
    total = total + score

avg = total / len(scores)
avg
77.5

On the first line, we define the temporary variable total (initially set to 0), which we’ll use to store the intermediate values of the sum after each iteration of the for loop. Next, the for-loop tells Python to go through the list scores. For each score in the list, we perform the operation total = total + score. When the for loop is finished, we have added all the scores to the total. In other words, we have obtained total = sum(scores). To obtain the average, we divide total by the length of the list.

Visit this link tinyurl.com/3bpx887v to see a step-by-step visualization of the for-loop execution, which shows how the variable total grows after each iteration of the loop. See also this blog post that talks about for-loops.

Loop variable names#

The name of the variable used for the for-loop is totally up to you, but you should choose logical names for elements of the list. For example, if the list is called objs, it makes sense to use obj as the name of the loop variable: for obj in objs: .... Given a list profiles, we would write the for-loop as for profile in profiles: .... Given a list nodes, we would use for-loop like for node in nodes: ..., etc.

List comprehension (bonus topic)#

Very often when programming, we need to transform a list of values, by applying the same function fun to each value in a list. Using the standard for-loop syntax, this operation requires four lines of code:

newvalues = []
for value in values:
    newvalue = fun(value)
    newvalues.append(newvalue)

This code uses a for-loop to apply the function fun to each element in the list values, and appends the transformed values to the list newvalues.

This type of code occurs so often that Python provides a shorthand syntax for describing this type of list transformations:

newvalues = [fun(value) for value in values]

This is called the “list comprehension syntax,” and is the preferred way to express simple list transformations, since it easier to read and fits on a single line. Here is an example, of applying of the function double to a list of five integers.

numbers = [1, 2, 3, 4, 5]
doubles = [double(number) for number in numbers]
doubles
[2, 4, 6, 8, 10]

Boolean variables and conditional statements#

Boolean variables represent logical conditions that are either True or False. We obtain boolean values when we perform numerical comparisons using the operators like <, >=, <=, == (equal to), != (not equal to).

x = 3
x > 2  # Is x greater than 2?
True

Another context where boolean values come up is when we use the in operator to check if an object is part of a list (or other container).

x = 3
x in [1,2,3,4]  # Is x in the list [1,2,3,4]?
True

Conditional statements#

Boolean values are used in conditional statements, which are blocks of Python code that may or may not be executed, depending on the value of a boolean value. The Python keywords if, elif, and else are used to create conditional statements.

Let’s start with some examples of if statements.

if True:
    print("this code will run")

if False:
    print("this code will not run")
this code will run

The indented code block inside an if statement is executed only when the if condition is True. We can extend an if statement with an else clause, which allows us to specify a different code block that will run if the condition is False.

x = 3
if x > 2:
    print("x is greater than 2")
else:
    print("x is less than or equal to 2")
x is greater than 2

We can check multiple conditions by using additional elif statements after the initial if, as shown in the next example.

temp = 8
if temp > 22:
    print("It's hot.")
elif temp < 10:
    print("It's cold.")
else:
    print("It's OK.")
It's cold.

When Python sees this if-elif-else statement, it checks all the if and elif conditions one-by-one, and if it finds a condition that is True, it will execute the corresponding code block. If none of the if and elif conditions are True, then the else code block will be run. At the end of this if-elif-else statement, exactly one of the print commands will be executed.

Exercise 7: Add another condition to the temperature code to print It's very hot! if the temperature is above 30.

temp = 33

# edit the code below to insert the new condition
if temp > 22:
    print("It's hot.")
elif temp < 10:
    print("It's cold.")
else:
    print("It's OK.")
It's hot.

Click for solution.

Boolean expressions#

You can use the logical operations and, or, and not to combine individual boolean values into larger boolean expressions that check multiple conditions. The result of an and operator (logical conjunction) is True only if both operands are true, and False otherwise, as shown in the following table.

Boolean expression

Value

True and True

True

True and False

False

False and True

False

False and False

False

The or operator (logical disjunction) will result in True as long as at least one operand is True:

Boolean expression

Value

True or True

True

True or False

True

False or True

True

False or False

False

The not operator performs the negation of a boolean value.

Boolean expression

Value

not True

False

not False

True

Here is an example of using the and operator to check two conditions simultaneously.

x = 3
x >= 0 and x <= 10
True

Try changing the value of x to make the boolean expression False.

Exercise 8: Water phases The phase of water depends on temperature. The three possible phases of water are "gas" (water vapour), "liquid" (water), and "solid" (ice). The table below shows the phase of water depending on the temperature temp, expresses as math inequalities.

Temperature range

Phase

temp >= 100

gas

0 <= temp < 100

liquid

temp < 0

solid

Fill in the if-elif-else statement below to print the correct phase depending on the variable temp.

temp = 90  # water temperature

# if ...:
#     print(....)
# elif ...:
#     print(....)
# else:
#     print(....)


# uncomment the code if-elif-else statement above and replace:
#   ... with conditions (translate math inequality into Python code),
#  .... with the appropriate phase string (one of "gas", "liquid", or "solid")

Click for solution.

Exercise 9: Assigning letter grades. Teacher Joelle has computed the final scores of the students as a percentage (a score out of 100). The school where she teaches requires her to convert each student’s score to a letter grade according to the following grading scale:

Grade

Numerical score interval

A

90% - 100%

B

70% - 89.999…%

C

50% - 69.999…%

F

0% - 49.999…%

Write an if-elif-elif-else statement that takes the score variable (a number between 0 and 100), and prints the appropriate letter grade for that score.

score = 90  # student score

# if ...:
#     print(..)
# elif ...:
#     print(..)
# elif ...:
#     print(..)
# else:
#     print(..)

# Uncomment the if-elif-.. statement and replace:
#    ... with the appropriate conditions,
#     .. with the appropriate letter grades

Click for solution.

Other data structures#

We already discussed lists, which are the most common data structure (container for data) in Python. In this section, we’ll briefly introduce some other Python data structures you might encounter.

Strings#

In Python, strings (type str) are the containers we use for storing text. We can create a string by enclosing text in single quotes ' or double quotes ".

message = "Hello everyone"
type(message)
str

String concatenation#

We can use string the + operator to concatenate (combine) two strings.

name = "Julie"
message = "Hello " + name + "!"
message
'Hello Julie!'

Strings behave like lists of characters#

You can think of the string "abc" as a list of three characters ["a", "b", "c"]. We can use list syntax to access the individual characters in the list. To illustrate this list-like behaviour of strings, let’s define a string of length 26 that contains all the lowercase Latin letters.

letters = "abcdefghijklmnopqrstuvwxyz"
letters
'abcdefghijklmnopqrstuvwxyz'
len(letters)  # length of the string
26

We can access the individual characters within the using the square brackets. For example, the index of the first letter in the string is 0:

letters[0]
'a'

The index of the letter "b" in the string letters is 1:

letters[1]
'b'

The last element in list of 26 letters has index 25

letters[25]
'z'

We can use the slice syntax to extract a substring that spans a certain range of indices. For example, the first four letters of the alphabet are:

letters[0:4]
'abcd'

The syntax 0:4 is a shorthand for the expression slice(0,4), which corresponds to the range of indices from 0 (inclusive) to 4 (noninclusive): [0,1,2,3].

Tuples#

A tuple is similar to a list, but with fewer features. The syntax for defining a tuples is base don the parentheses, and the elements of the tuple are separated by commas.

(1, 2, 3)
(1, 2, 3)

Actually, the parentheses are optional: we can define a tuple by using writing a bunch of commas-separated values.

1, 2, 3
(1, 2, 3)

I want you to know about this comma syntax, because it is very convenient for printing several values at the end of a code cell in a notebook environment. For example, here is how we can display the first, second, and last characters from the string letters on a single line.

letters[0], letters[1], letters[25]
('a', 'b', 'z')

Dictionaries#

One of the most useful data structure when programming is the associative array, which is called a dictionary (dict) in Python. A dictionary is a container of key-value pairs. We use the keys to access the different values in the container. For example, the code below defines the dictionary profile that contains three keys-value pairs.

profile = {"name":"Julie", "age":31, "score":98}
profile
{'name': 'Julie', 'age': 31, 'score': 98}

The syntax for creating a dictionary is based on "key": value pairs, separated by commas, wrapped in curly braces { and }. The keys of the profile dictionary are "name", "age", and "score".

profile.keys()
dict_keys(['name', 'age', 'score'])

The values associated with these keys are "Julie" (a string), 31, and 98 (integers).

profile.values()
dict_values(['Julie', 31, 98])

We access the value in the dictionary using the square brackets syntax. For example, to get the value associated with key "score", we use:

profile["score"]
98

Recall, we used the square bracket syntax earlier for accessing the values within a list. Indeed, lists and dictionaries are both containers objects, and we use square brackets syntax to access elements within them.

You can change the value associated with a key by assigning a new value to it, as follows:

profile["score"] = 77
profile
{'name': 'Julie', 'age': 31, 'score': 77}

You can also add a new key-value pair to the dictionary by assigning a value to a key that doesn’t exist yet:

profile["email"] = "julie@site.org"
profile
{'name': 'Julie', 'age': 31, 'score': 77, 'email': 'julie@site.org'}

Note the profile dictionary now has a new key "email" and the value "julie@site.org" stored under that key.

Exercise 10: Creating a new profile dictionary#

Create a new dictionary called profile2 with the same keys as dictionary profile for the user "Alex" who has age 42 and score 65.

profile2 = ...  # replace ... with your answer

Click for solution.

Type conversions#

We sometimes need to convert between variables of different types. The functions for conversing types have the same name as the object types:

  • int : converts any expression into an int

  • float: converts any expression into a float

  • str: converts any expression into a str

For example, suppose you’re given the number "42.5" as a string.

type("42.5")
str

To convert this string to a floating point number, we can call the function float.

f = float("42.5")
f
42.5
type(f)
float

Now that we have converted the string "42.5" to the float 42.5, we can do numerical operation like +, -, and * with this number.

Example 7: Compute the sum of two numbers#

Suppose we’re given two numbers \(m\) and \(n\), and we want to compute their sum \(m+n\). However, the numbers \(m\) and \(n\) are given to us as strings, so we don’t get the expected result when we add them together.

mstr = "2.1"
nstr = "3.4"
mstr + nstr
'2.13.4'

This is because the addition operator + for strings means concatenate, not add. We have to manually convert the strings to numbers, if we want to add them together as numbers.

mfloat = float(mstr)
nfloat = float(nstr)
mfloat + nfloat
5.5

Exercise 11. Write the Python code that converts values in the list prices to floating point numbers and adds them together.

Hint: use a for-loop or the list comprehension syntax.

prices = ["22.2", "10.1", "33.3"]

# write the code to compute the total price

Click for solution.

Python packages and modules#

All the code examples we showed above were using the Python built-in functions and data types, but that is only a small part of the functionality available in Python. There are hundreds of Python packages and modules that provide additional functions and data types for all kinds of applications. There are Python modules for processing different data files, making web requests, doing efficient numerical computing, calculating statistics, etc. The list is almost endless!

Import statements#

We use the import keyword to load a Python module and make it available in the current notebook environment. The command to import the module <module> in the current context is:

import <module>

After this import statement, we can use the all functions from the module <module> by calling them using the prefix <module>., which is called the “dot notation” for accessing names within the <module> namespace. For example, here is how we can import the statistics module and use the function statistics.mean to compute the mean of a list of numbers.

import statistics
statistics.mean([1,2,3,4])
2.5

Alias import statements#

A very common trick you’ll see in many Python notebooks, is to import python modules under an “alias” name, which is usually a shorter name that is faster to type. The alias-import statement looks like this:

import <module> as <mod>

For example, importing the statistics module under the alias stats looks like this.

import statistics as stats
stats.mean([1,2,3,4])
2.5

The alias-import statement allows us to use the shorter names stats.mean and stats.median instead of typing out the full module name each time, like statistics.mean and statistics.median. In data science, it is very common to alias-import the numpy module as np, the pandas module as pd, and the seaborn module as sns.

Selective import statements#

It is also possible to import only a specific function from a module using the following syntax.

from <module> import <function>

This allows you to use <function> directly in your code, without the <module>. prefix.

from statistics import mean
mean([1,2,3,4])
2.5

The standard library#

The Python standard library refers to the hundreds of Python modules that come bundled with every Python installation. Here are some of the most commonly used modules from the standard library:

  • math: math functions like sqrt, sin, cos, etc.

  • random: random number generation

  • statistics: descriptive statistics functions

  • datetime: manipulate dates and times

  • urllib: tools to manipulate URLs

  • json: read and write JSON files

  • csv: read and write CSV files

  • sys: access information about the current process

  • os: interface with the operating system and file system paths

  • re: regular expressions patterns for text processing

The easy of access to all these modules with thousands of predefined functions is a big reason why Python is popular today. Python is often described as a language that comes with “batteries included” because of all the functionality available in the standard library.

Installing packages using pip#

In addition to the standard library, the Python ecosystem includes a vast ecosystem of third-party modules, which you can install using the pip command-line tool. Normally, using pip requires some familiarity with command-line interface tools, but when working in a JupyterLab environment, you can use the magic command %pip right within a notebook. To install Python package named <pkgname>, run the command %pip install <pkname> in a notebook code cell. For example, here is the %pip command for installing the sympy package.

%pip install sympy
Requirement already satisfied: sympy in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (1.12)
Requirement already satisfied: mpmath>=0.19 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from sympy) (1.3.0)
[notice] A new release of pip is available: 23.0.1 -> 24.0
[notice] To update, run: pip install --upgrade pip
Note: you may need to restart the kernel to use updated packages.

In this case, the message “Requirement already satisfied: sympy” tells us that the sympy package is already installed, so there is nothing to do. If the sympy was not present, however, the %pip command search for the sympy package published on the Python Package Index website (see https://pypi.org/project/sympy/), download the latest version, and install it so that it is available for use (e.g. import sympy etc.).

The breadth and depth of the modules in the Python ecosystem is staggering. Whether you’re an astrophysicist analyzing data from deep space, a neuroscientist who is trying to decode neural activity, or an office worker trying to process some obscure file format, there is a good chance that someone has come before you and written code you can reuse for your task. A detailed discussion of the Python third-party modules ecosystem is outside the score of this introductory tutorial, but I’d like to mention a few of the all-star, heavy-hitter libraries for scientific computing and data science.

Scientific computing libraries#

Python was adopted by the scientific community very early on, because it is an easy language to learn. Scientific computing usually involves large-scale numerical calculations on vectors and matrices, which led to the development of the following packages for high-performance computing:

  • Numerical Python (numpy) is a library that provides array and matrix objects that make mathematical operations run very fast.

  • Scientific Python (scipy) is a library provides many functions used by scientists and engineers. The module scipy.stats contains all the probability models we use in statistics.

  • Symbolic Python (sympy) is a library for symbolic math calculations. Using SymPy you can work with math expressions just like when solving math problems using pen and paper. See the sympy_tutorial.pdf to learn more about SymPy.

Data science libraries#

Another community where Python is very popular is among statisticians and data analysts, which is thanks to the following libraries for data handling and visualization:

  • Pandas (pandas) is a library for tabular data management. Pandas is the Swiss army knife of data manipulations, and provides functions for loading data from various formats, and doing data processing, data cleaning, and calculating descriptive statistics. See the pandas_tutorial.ipynb notebook to learn more about Pandas.

  • Seaborn (seaborn) is a high-level library for statistical plots. Seaborn allows you to generate beautiful data visualizations like strip plots, scatter plots, histograms, bar plots, box plots, etc. See the seaborn_tutorial.ipynb notebook to learn more about Seaborn.

  • Statsmodels (statsmodels) is a statistical modelling library that includes advanced statistical models and functions for performing statistical tests.

TODO: closing sentence

Getting comfortable with Python#

JupyterLab provides lots of tools for making learning Python easy for beginners, including documentation (help menus) and interactive ways to explore variable properties.

Showing the help info#

Every Python object has a “docstring” (documentation string) associated with it, which provides the help info about this object. There are three equivalent ways to view the docstring of any Python object obj (value, variable, function, module, etc.):

  • help(obj): shows the docstring for the object obj

  • obj?: shortcut for help(obj)

  • press SHIFT+TAB: while the cursor is on top of a variable or function inside a code cell.

There are also other methods for getting more detailed info about an object like obj??, %psource obj, %pdef obj, but we won’t need these for now.

Example 8: Learning about the print function#

Let’s say want to learn more about the print function. Put the cursor in the middle of function and press SHIFT+TAB.

print
<function print>

You know this function accepts one or more arguments and displays them, but the help menu shows complete information about other keywords arguments (options) you can use when calling this function. You can also use the help function to see the same information.

help(print)
Help on built-in function print in module builtins:

print(...)
    print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
    
    Prints the values to a stream, or to sys.stdout by default.
    Optional keyword arguments:
    file:  a file-like object (stream); defaults to the current sys.stdout.
    sep:   string inserted between values, default a space.
    end:   string appended after the last value, default a newline.
    flush: whether to forcibly flush the stream.

The ... in the doc string of the print function tells us it accepts multiple values. The keyword argument sep (separator) dictates the text that is inserted between values when they are printed, The keyword end controls what is printed at the end of the line (\n means newline). Note we could have obtained the doc string using print? or using print(print.__doc__).

Exercise 12: Display the doc-string of the function len.

len
<function len(obj, /)>

Click for solution.

Inspecting Python objects#

Suppose you have an unknown Python object obj. How can you find out what it is and learn what you can do with it?

Displaying the object#

There are several ways to display information about the object obj.

  • print(obj): converts the object to str and prints it

  • type(obj): tells you what type of object it is

  • repr(obj): similar to print, but shows the complete text representation (including quotes). The output of repr(obj) usually contains all the information needed to reconstruct the object obj.

Auto-complete object attributes and methods#

JupyterLab code cells provide an “autocomplete” feature for exploring the attributes and methods objects. To use the autocomplete functionality, start obj. then press TAB button, and you will be presented with all the options available. Try it.

message = "Hello everyone"
# message.    # place cursor after the dot and press the TAB button

This autocomplete feature is used very often by programmers to find the attributes and methods they need to access. Examples of useful methods on the message object include message.upper(), message.lower(), message.split(), message.replace(...), etc.

Python error messages#

Sometimes your code will cause an error and Python will display an error message describing the problem it encountered. You need to be mentally prepared for these errors, since they happen a lot and can be very discouraging to see. Examples of errors include SyntaxError, NameError, TypeError, etc. Error messages look scary, but really they are there to help you—if you read what the error message is telling you, you’ll know exactly what you need to fix in your code. The error message literally describes the problem!

Let’s look at an example expression that causes a Python exception. Suppose you’re trying to compute the difference 5-3, but you forgot the minus sign.

5 3
  Cell In[82], line 1
    5 3
      ^
SyntaxError: invalid syntax

The code cell above shows an example of a SyntaxError that occurs because Python expects some operator or separator between the two numbers. Python doesn’t know what to do when you just put two numbers side-by-side, and it doesn’t want to guess what your intention was (53? 5.3?).

You’ll see these a threatening looking red message like this any time Python encounters an error while trying to run the commands you specified. We say the code “raises” or “encountered” an exception. This is nothing to be alarmed by. It usually means you made a typo, forgot a required syntax element, or tried to compute do something impossible. The way to read these red messages is to focus on the explanation message that gets printed on the last line. The error message usually tells you what you need to fix. The solution will be obvious when you have made a typo or a syntax error, but in more complicated situations, you might need to search for the error message online to find what the problem is. In the above example, the fix is simple: we just need to add the missing minus sign: 5-3.

The three most common Python error messages are:

  • SyntaxError: you typed in something wrong (usually missing ,, ", or ] or some other punctuation).

  • NameError: raised when a variable is not found in the current context.

  • TypeError: raised when a function or operation is applied to an object of incorrect type.

Later on you might run into: KeyError when a key is not found in a dictionary, ValueError when a function gets an argument of correct type but improper value, ImportError when importing modules, and AttributeError when trying to access an object attribute that doesn’t exist.

Exercise 13: Let’s break Python! Try typing in Python commands that causes each of these exceptions:

  1. SyntaxError (hint: write an incomplete list expression)

  2. NameError (hint: try referring to a variable that doesn’t exist)

  3. TypeError (hint: try to sum something that is not a list)

Click for solution.

Python documentation#

The official Python documentation website is https://docs.python.org. This website provides tons of excellent learning resources and reference information for learning Python. Here are some useful links to essential topics for Python beginners:

I encourage you to browse the site to familiarize yourself with the high quality information that is available in the official docs pages.

When searching online, the official Python docs might now show up on the first page of results. Because of Python’s popularity, there are hundreds of spammy websites that provide inferior information, wrapped in tons of advertisements and popups. These websites that are much inferior to the official documentation. When learning something new, you should always prefer the official docs, even if they don’t appear first in the list of results on the page. Stack overflow discussions can be a good place to find answers to common Python questions. ChatGPT is also pretty good with Python code, so you can ask it to give you code examples or provide feedback on code you’ve written.

Final review#

Let’s do a quick review of all the Python concepts we introduced in this tutorial.

Python grammar and syntax review#

Learning Python is like learning a new language:

  • nouns: variables and values of different types

  • verbs: functions and methods, including basic operators like +, -, etc.

  • grammar: rules about how to use nouns and verbs together

Python keywords#

Here is a complete list of keywords in the Python language:

False      class      finally    is         return
None       continue   for        lambda     try
True       def        from       nonlocal   while
and        del        global     not        with
as         elif       if         or         yield
assert     else       import     pass
break      except     in         raise

As you can see from the above list, there are some keywords that we didn’t cover in this tutorial, because they are not essential to know at first. Here is the shortlist of the keywords you need to remember:

  • def used to define a new function and the return statement that defines the output of the function

  • in to check if element is part of container

  • for used in for-loops and list-comprehension syntax

  • the boolean values True and False

  • or, and, and not to create boolean expressions

  • if, elif, else used in conditional statements

  • None is a special keyword that represents the absence of a value

  • import ... and from ... import ... statements to import Python modules

Python data types#

Here is a reminder of the Python built-in data types:

  • int: integers

  • float: decimals

  • list: list of objects [obj1, obj2, obj3, ...]

  • bool: boolean values (either True or False)

  • str: text strings

  • dict: associative array between keys and values

  • tuple: similar to a list, but cannot be modified

Python functions#

Here are the essential functions you need to remember:

  • print(arg1,arg2, ...): print str(arg1), str(arg2), ... to the screen

  • type(obj): tells you what kind of object

  • len(obj): length of the object (only for: str, list, dict objs)

  • range(a,b): creates a list of numbers [a,a+1,...,b-1]

  • help(obj): display info about the object, function, or method

Here is another set of build-in functions used for lists, and list-like objects:

  • len(mylist): length of the list mylist

  • sum(mylist): sum of the values in the list of numbers mylist

  • all(mylist): True if all values in the list mylist are True

  • any(mylist): True if any of the values in the list mylist are True

  • enumerate(mylist): convert list of values to mylist to list of tuples (i,mylist[i]). Used to know the index in for-loop, e.g. for i, item in enumerate(items): ....

  • zip(list1,list2): joint iteration over two lists

  • Low-level iterator functions: iter() and next()

The function for input/output (I/O) operations are:

  • input: prompt the user for text input

  • print(arg1,arg2, ...): print str(arg1), str(arg2), ... to the screen or file

  • open(filepath,mode): open the file at filepath for reading or writing. Use mode="r" for reading or mode="w" for writing.

Here are some functions you can use when “looking around” to find more information about objects:

  • str(obj): display the string representation of the object.

  • repr(obj): display the Python representation of the object. Usually, you can copy-paste the output of repr(obj) into a Python shell to re-create the object.

  • help(obj): display info about the object, function, or method. This is equivalent to printing object’s docstring obj.__doc__.

  • dir(obj): show complete list of attributes and methods of the object obj

  • globals(): display all variables in the Python global namespace

  • locals(): display local variables (within current scope)

Advanced functions:

  • Functional stuff: map(), eval(), exec()

  • Meta-programming: hasattr(), getattr(), setattr()

  • Object oriented programming: isinstance(), issubclass(), super()

Python punctuation#

The most difficult part of learning Python is the use of non-word punctuation characters, which have very specific meaning and take some time to get used to. Let’s review and summarize how the symbols =([{*"'#,.: are used in Python.

  • The hash symbol # is used for comments.


  • Asterisk * is the multiplication operator, while the double asterisk ** is the exponent operator.


  • Equal sign = is used for:

    • assignment statements: x = 5

    • pass keyword arguments to functions: print("ans",3,sep=":")

    • (advanced) specify default keyword argument in function definitions


  • The comparison operators <, >=, <=, == (equal to), and != (not equal to) are used compare relative size of numerical values: x > 2.


  • Parentheses () are used for:

    • function definitions: def fun(x): ...)

    • calling functions: print(3)

    • enforcing order of operations: (x + y) * z

    • defining tuples: (1, 2, 3)


  • Comma , is used as:

    • element separator in lists, tuples, sets, etc.

    • separator between key:value pairs when defining a dictionary

    • separate function arguments in function definitions

    • separate function arguments when calling functions


  • Curly-brackets (accolades) {} are used to

    • define dictionaries: mydict = {"key":"value", "k2":"v2"}

    • define sets: {1,2,3}


  • Square brackets [] are used for:

    • defining lists: mylist = [1, 2, 3]

    • accessing list elements: mylist[2]

    • list slicing: mylist[0:2] = first two items in mylist

    • accessing dictionary values by key: mydict["key"]


  • Quotes " or ' are used to define string literals. There are several variations you can use:

    • raw strings r"..." are be used for reduce escape characters

    • f-strings f"..." are used to include variables

    • triple quotes """ or ''' are used to define entire paragraphs


  • Colon : is used for:

    • starting an indented code block in statements like if, elif, else, for, etc.

    • key: value separator in dict literals

    • slice notation: 0:2 == slice(0,2) == [0,1]


  • Period . is used as:

    • decimal separator for floating point literals: 4.2

    • access object attributes and methods: msg.upper()

    • access names within a namespace: statistics.mean


  • Semicolon ; can be used to put multiple commands on single line.
    We sometimes use ; at the end of a line to suppress the output of a command in a notebook environment.

Applications#

I want to tell you about some of the cool Python applications you can look forward to if you choose to develop your Python skills further. Python is not just a calculator, but a general-purpose programming language, so it can be used for many applications. We already mentioned Python uses in scientific computing and data science. Here are some other areas where Python programming is popular.

  • Command line scripts: you can put Python commands into a script, then run them on the command line (terminal in UNIX or cmd.exe in Windows). For example, you can write a simple script that downloads music videos from YouTube and saves them as .mp3 files you can listen to offline.

  • Graphical user interface (GUI) programs: many desktop applications are written in Python. An example of a graphical, point-and-click application written in Python is Calibre, which is a powerful eBook management library, eBook reader, and eBook converter that supports every imaginable eBook format.

  • Web applications: the Django and Flask frameworks are often used to build web applications. Many of the websites you access every day have as server component written in Python.

  • Machine learning: most of the current machine learning (a.k.a. artificial intelligence) research and development is done using Python code.

  • Glue code: whenever you have some process that needs to take data from one place and bring it into another program, Python is a good choice to automate this process.

  • Cloud automation: you can use Python scripts to automate the entire IT infrastructure of a company.

I mention these examples so you’ll know the other possibilities enabled by Python, beyond the basic “use Python interactively like a calculator” code examples that we saw in this tutorial. We’re at the end of this tutorial, but just the beginning of your journey to discover all the interesting things you can do with Python.