CoCalc Public FilesNotes.ipynbOpen with one click!
Author: Johann Thiel
Views : 950
Compute Environment: Ubuntu 20.04 (Default)
In [ ]:


This notebook will contain brief notes on topics covered in the course.

Data Types, Operators, Expressions, and Comparisons

Data Types

There are many different classes of objects in Python. We will not cover all of them here. Below is a short list of some of the basic objects (datatypes) we will commonly use:

  • int: Integers like ...,-2, -1, 0, 1, 2.... There is a limit to how large these can be and you must be careful about what happens when you use division.

  • float: Floating point numbers have a decimal part like 2.1 and 3.000023. Because the computer uses binary to represent numbers, not every number can be perfectly represented by a float.

  • bool: Boolean variables are either True or False and can be used to compare other data types.

  • list: A list is an ordered collection of objects. These are typically used if you need to repeat a procedure. For example [1,2,3,5] is a list. Note: lists use square brackets and can contain different data types.

  • string: A string is essentially a list of characters. For example, 'python' is a string. Note: the int 1 is different from the char '1'.

You can figure out an objects type by using the type() function.

In [1]:
In [2]:
In [3]:
In [4]:
In [5]:

Operators and Expressions

Operators allow you to take data types and manipulate their values. The same symbol may do different things depending on the data types used as inputs. Expressions are just how we tell the computer what we would like it to do.

In [6]:
3 + 4
In [7]:
3 / 2
In [8]:
[1,2,3] + [4,5,6]
[1, 2, 3, 4, 5, 6]
In [9]:
'python' + ' ' + 'is great'
'python is great'
In [10]:
3 + 4 * 2


Comparisons are expressions that usually evaluate to True or False. We use these when writing code that reacts to a given input.

In [11]:
3 <= 4
In [12]:
'Hello' == 'hello'


Variables act as a storage or placeholder for different data types that allows us to write abstract code that can handle a unknown input values. Variable names are case sensitive and cannot begin with a number. There are a few other rules regarding variable names. As the scope of your project grows, make sure to use long, descriptive variable names to help. Note that = is different from ==. In particular, = assigns the value on the right to the variable on the left, while == returns a boolean value when comparing the objects on the right and left.

In [13]:
x = 2
In [14]:
x + 3
In [15]:
x = x + 1
In [16]:
In [17]:
y = x
In [18]:
In [19]:
y == x


Functions are helpful in that they allow you to write code that can be easily reused. Instead of writing the same block of code multiple times in a program (if needed), use a function. Note that in Python, whitespace is critical. Indented lines are considered to be part of the function, while lines that line up with the function definition line do not.

The basic structure is:

def function_name(input_variable1, input_variable2,...):
    return output
In [20]:
def square(n): return n*n
In [21]:
In [22]:

Control Flow: If/Elif/Else and Loops


If/Elif/Else statements are useful whenever we need a program that reacts to some input. Note the importance of whitespace here as well. For example, the absolute value function is defined as x={x if x0x otherwise.|x|=\begin{cases}\phantom{-}x & \text{ if $x\geq 0$}\\-x & \text{ otherwise.}\end{cases}

The basic structure is:

if comparison:

If the comparison is true, code1 executes. Otherwise, code2 executes. If more than two options are needed, use elif with additional comparisons.

if comparison1:
elif comparison2:
In [23]:
x = -3 if x >= 0: print(x) else: print(-x)

More on Lists and Strings

Lists and strings are very similar and share a lot of similar behavior/operators. When assigning a list or string to a variable, we can extract portions of the list of string using indexing. Remember that Python is zero indexed. Negative numbers may be used to select items counting from right to left rather thant he usual left to right.

In [24]:
my_list = [1,5,7,3,9] my_string = 'quick'
In [25]:
In [26]:

Lists and strings allow for slicing, which produces a copy of the list or string containing the subset of elements listed.

The usual notation is:

variable_name[start:stop + 1: step_size]

Blanks may be used for the start and stop portion to indicate that you want to start from the beginning or go to the very end. A negative step size reverses the direction of the list or string.

In [27]:
[7, 3]
In [28]:
In [29]:
[1, 7, 9]
In [30]:
[9, 3, 7, 5, 1]

While Loops

While loops are useful when you need to repeat some procedure but are not sure of how many iterations will be needed. In many situations, while and for loops are interchangable.

The basic structure is:

while comparison:

The code inside the while loop will continue to be executed until the comparison is false. That means it is up to you to update the variables associated with the comparison unless you want a loop that either never runs or runs forever.

In [31]:
n = 1 while n <= 10: print(n) n += 1
1 2 3 4 5 6 7 8 9 10

For Loops

A for loop is useful when you you would like to compute something repeatedly based on each element in a list, string, or other iterable.

The basic structure is:

for variable in iterable:

If your iterable is a list of numbers or a string, then we can perform a common operation based on each individual element in the list or string.

In [32]:
for x in [1,2,3,4,5]: print(-x)
-1 -2 -3 -4 -5
In [33]:
for c in 'Hello there!': print(c)
H e l l o t h e r e !

The following example combines the length function with string indexing. It accomplishes the same thing as the previous loop.

In [34]:
s = 'Hello there!' for i in range(len(s)): print(s[i])
H e l l o t h e r e !
In [35]:
for x in my_list: print(1/x)
1.0 0.2 0.14285714285714285 0.3333333333333333 0.1111111111111111
In [36]:
for y in my_string: print(y.upper())

Compound Interest

The basic formula for compound interest:


P=P = principal

r=r = annual interest rate

n=n = number of compoundings per year

c=c = contribution for principal per compounding period

P=P' = new principal after one compounding period


Recursion involves objects whose definitions refer to themselves.

  • Recursion is useful when solving a problem whose solution involves first solving a “smaller” version of the same problem.

  • Recursive definitions involve two key ingredients:

    1. A base case – this is an initial case or cases used to compute an answer.
    2. An inductive case – this case tells you how to reduce the current case to previous cases.

Below we give a recursive definition of the function that computes the minimum number of moves needed to solve the Tower of Hanoi problem with nn discs.

In [4]:
def hanoi(n): if n == 1: return 1 else: return 2*hanoi(n-1)+1 hanoi(7)

Basic Plotting

We will use the Matplotlib library for basic plotting. Matplotlib is not available by default in Python and must be imported. The general idea is that you issue various commands that modify a plot until you are satisfied with the results. There are a wide variety of options. The recommendation is that you use the Matplotlib website for help. Do not attempt to memorize all of Matplotlib.

In [1]:
import matplotlib.pyplot as plt x = [1,2,3] y1 = [3,5,2] y2 = [-3,2,5] plt.scatter(x,y1,color='red',label='y_1') plt.scatter(x,y2,label='y_2') plt.xlabel('x') plt.ylabel('y') plt.legend() plt.title('y vs. x')
Text(0.5, 1.0, 'y vs. x')

List Comprehensions

A list comprehension if a shortcut that allows you to create lists of elements using notation similar to set-builder notation.

The basic structure is:

[expression(var) for var in iterable if condition]

This is equivalent to:

L = []
for var in iterable:
    if condition:

The list comprehension below contains the set of odd cubes from 0 to 1000.

In [2]:
[x**3 for x in range(10) if x%2==1]
[1, 27, 125, 343, 729]

Bisection Method

We use the Bisection Method to estimate the roots of a continuous function f(x)f(x). This is done in the following way:

  1. Select a tolerance level for the error in our approximation.
  2. Find real numbers aa and bb so that f(a)f(b)<0f(a)f(b) < 0.
  3. Compute c=a+b2c=\frac{a+b}{2}.
  4. If cac-a is smaller than the tolerance level for the error, stop and return cc as an approximation of a root of ff.
  5. If f(c)=0f(c)=0, we have found a root and we stop.
  6. If f(a)f(c)>0f(a)f(c) > 0, set a=ca = c. Otherwise set b=cb=c and return to step 2.
In [5]:
def bisection(a,b,f,err): c = (a+b)/2 while c-a > err: if f(c) == 0: return n elif f(c)*f(a) > 0: a = c else: b = c c = (a+b)/2 return c def root2(n): return n*n-2 bisection(0,2,root2,0.0001)