CoCalc Shared FilesTutorial Zero / Python Review.ipynb
Author: Karl Ang
Views : 98
Description: Jupyter notebook Tutorial Zero/Python Review.ipynb

# Markdown cell demo

This is a markdown (text) cell!

# Code cell demo

In [250]:
print("This is a code cell!")
print("This is another line in the code cell!")

This is a code cell! This is another line in the code cell!

# Python basics

In [260]:
# this is a comment, it doesn't do anything

In [261]:
print(1)

1
In [1]:
print(39.01)

39.01
In [263]:
print("hello, world!")

hello, world!
In [2]:
print "hello, world!"

 File "<ipython-input-2-a2f0334f2607>", line 1 print "hello, world!" ^ SyntaxError: Missing parentheses in call to 'print'. Did you mean print("hello, world!")? 

Notice that when you use print, there is no Out[] prompt, but if you just have number on a line by itself, there is:

In [5]:
1

1
In [4]:
39.01

39.01
In [3]:
"hello, world!"

'hello, world!'

The difference is that you can use print anywhere, but having something on a line by itself must be the last line in the cell:

In [268]:
print(1)
print(39.01)
print("hello, world!")

1 39.01 hello, world!
In [269]:
1
39.01
"hello, world!"

'hello, world!'

## Math operations

You can use Python just like a calculator! Just write math how you'd write it normally:

In [270]:
1 + 2

3
In [271]:
7 * 5

35
In [272]:
3 / 2 # watch out -- this won't work on Python 2!

1.5
In [273]:
83 - 21

62
In [274]:
-5

-5
In [275]:
1 - -2

3

One exception is exponents. If I want to do $3^2$, I need to use double asterisks **:

In [276]:
3 ** 2

9
In [6]:
3 ^ 2 # this will not do what you think! this is a bitwise xor!

1
In [7]:
0b11 ^ 0b10

1

## Order of operations

If you're doing multiple operations, be careful about the order! Operations take precedence in this order:

1. Negation (e.g. -4)
2. Exponents (e.g. 3 ** 2)
3. Multiplication and division (e.g. 4 * 5 or 4 + 5)
4. Addition and subtraction (e.g. 8 + 3 or 8 - 3)

It is a good rule of thumb to always use parentheses to group things in the way you want them:

In [279]:
(4 + 0.9) * (2 + 0.1)

10.290000000000001

If you leave off the parentheses, you might get a different answer!

In [280]:
4 + 0.9 * 2 + 0.1

5.8999999999999995

This is equivalent to the version without parentheses:

In [281]:
4 + (0.9 * 2) + 0.1

5.8999999999999995

## Variables

Variables in Python can store any value:

In [282]:
my_variable = 1


Once defined, they can be used just like the values we had above:

In [283]:
my_variable

1

However, if a variable is not defined, you will get an error:

In [8]:
y

--------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-8-9063a9f0e032> in <module> ----> 1 y NameError: name 'y' is not defined 

A variable is "defined" the first time you give it a value, not the first time you use it. To give y a value, we just need to put something to the right of the equals sign:

In [285]:
y = 2


Then we can look at its value:

In [286]:
y

2

# Datatypes

## Numbers

This is an integer:

In [287]:
83

83
In [288]:
type(83)

int

Numbers that have a decimal are floats:

In [289]:
83.0

83.0
In [290]:
type(83.0)

float

Using type can be espcially useful if you have a variable:

In [291]:
y

2
In [292]:
type(y)

int

## Booleans

Booleans are true/false values. They get special symbols (note that the case matters):

In [293]:
True

True
In [294]:
False

False
In [295]:
true

--------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-295-74d9a83219ca> in <module>() ----> 1 true NameError: name 'true' is not defined 

## Strings

Strings get wrapped in quotes, like this:

In [296]:
"I am a string"

'I am a string'
In [297]:
'I am a string'

'I am a string'

If you forget the quotes, you'll get an error (in this case, a SyntaxError, because it expects there to be operators between the symbols I, am, a, and string):

In [298]:
I am a string

 File "<ipython-input-298-4cb504e04f59>", line 1 I am a string ^ SyntaxError: invalid syntax 

We can have multline strings as well:

In [299]:
"""I am a string"""

'I am a string'
In [300]:
'''I am a string'''

'I am a string'
In [12]:
"""I am a
multiline
string"""

'I am a\nmultiline\nstring'
In [10]:
print("""I am a
multiline
string""")

I am a multiline string
In [303]:
print("I am a\nmultiline\nstring")

I am a multiline string
In [13]:
"I am a
multiline
string"

 File "<ipython-input-13-5a80c8e0251e>", line 1 "I am a ^ SyntaxError: EOL while scanning string literal 

You can do addition and multiplication with strings!

In [305]:
"foo" + "bar"

'foobar'
In [306]:
"foo" * 5

'foofoofoofoofoo'

You can also turn other things into strings with str:

In [307]:
str(1)

'1'
In [308]:
str(45.0234)

'45.0234'

Be careful, though, because if you are doing addition and want it to be numerical addition, but you have strings, you won't get what you want:

In [309]:
str(1) + str(45.0234)

'145.0234'

## Lists

Lists are ways that we can group variables together:

In [15]:
list_of_fruits = ["apple", "banana", "orange"]
list_of_fruits

['apple', 'banana', 'orange']

We can add items to the list with append:

In [16]:
list_of_fruits.append("pear")
list_of_fruits

['apple', 'banana', 'orange', 'pear']

Or insert items elsewhere with insert:

In [17]:
list_of_fruits.insert(1, "pineapple")
list_of_fruits

['apple', 'pineapple', 'banana', 'orange', 'pear']

You can remove items with remove:

In [18]:
list_of_fruits.remove("banana")
list_of_fruits

['apple', 'pineapple', 'orange', 'pear']

### Looking up items

You can check if an item is in a list using the in keyword:

In [314]:
'pineapple' in list_of_fruits

True
In [315]:
'banana' in list_of_fruits

False

To retrieve an item, you can use square brackets, and then the index of the item:

In [316]:
list_of_fruits[0] # the first element

'apple'
In [317]:
list_of_fruits[1] # the second element

'pineapple'

There is a special syntax for getting the las element of the list, which is to use an index of -1:

In [318]:
list_of_fruits[-1] # the last element

'pear'

You can also slice a range of elements using slice syntax, which is:

• [i] -- get the element at index i
• [:j] -- get all elements up to (and excluding) index j
• [i:j] -- get all elements between index i and index j (including i, excluding j)
• [i:j:k] -- get every kth element between index i and index j (including i, excluding j)
• [:j:k] -- get every kth element up to (and excluding) index j
• [::k] -- get every kth element in the entire list
In [319]:
list_of_fruits

['apple', 'pineapple', 'orange', 'pear']
In [320]:
list_of_fruits[:2]

['apple', 'pineapple']
In [321]:
list_of_fruits[1:3]

['pineapple', 'orange']
In [322]:
list_of_fruits[1:4:2]

['pineapple', 'pear']
In [323]:
list_of_fruits[:2:2]

['apple']
In [324]:
list_of_fruits[::2]

['apple', 'orange']
In [325]:
list_of_fruits[::-1]

['pear', 'orange', 'pineapple', 'apple']

We can create a list of numbers using a similar syntax:

• range(i) -- all integers from 0 to i (excluding i)
• range(i, j) -- all integers between i and j (including i, excluding j)
• range(i, j, k) -- every kth integer between i and j (including i, excluding j)
In [326]:
range(10)

range(0, 10)
In [327]:
list(range(10))

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

### Modifying list items

Using this same notation, we can also set elements:

In [19]:
list_of_fruits

['apple', 'pineapple', 'orange', 'pear']
In [20]:
list_of_fruits[1] = 'banana'
list_of_fruits

['apple', 'banana', 'orange', 'pear']

Unlike in MATLAB, if you try to set an element that doesn't exist, Python will complain at you:

In [21]:
list_of_fruits[4] = 'grape'

--------------------------------------------------------------------------- IndexError Traceback (most recent call last) <ipython-input-21-df80e8b1657e> in <module> ----> 1 list_of_fruits[4] = 'grape' IndexError: list assignment index out of range 
In [22]:
list_of_fruits.append('grape')
list_of_fruits

['apple', 'banana', 'orange', 'pear', 'grape']

### Gotcha: lists are passed by reference

If you have one list, and want to create a copy of that list, you can't just assign it to a new variable:

In [23]:
list_of_fruits

['apple', 'banana', 'orange', 'pear', 'grape']
In [24]:
list_of_citrus = list_of_fruits
list_of_citrus[0] = 'lemon'
list_of_citrus[1] = 'lime'
list_of_citrus[3] = 'mandarin'
list_of_citrus

['lemon', 'lime', 'orange', 'mandarin', 'grape']
In [25]:
list_of_fruits

['lemon', 'lime', 'orange', 'mandarin', 'grape']

Instead, you have to copy the list by using .copy():

In [26]:
list_of_fruits = ['apple', 'banana', 'orange', 'pear']

In [27]:
list_of_citrus = list_of_fruits.copy()
list_of_citrus[0] = 'lemon'
list_of_citrus[1] = 'lime'
list_of_citrus[3] = 'mandarin'
list_of_citrus

['lemon', 'lime', 'orange', 'mandarin']
In [28]:
list_of_fruits

['apple', 'banana', 'orange', 'pear']

## Tuples

Tuples act exactly the same as lists, except that they are denoted with parentheses (instead of square brackets) and you can't modify them:

In [29]:
tuple_of_fruits = ("apple", "banana", "orange")
tuple_of_fruits

('apple', 'banana', 'orange')
In [30]:
tuple_of_fruits.append("pear")

--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-30-1972f4654a5f> in <module> ----> 1 tuple_of_fruits.append("pear") AttributeError: 'tuple' object has no attribute 'append' 
In [31]:
tuple_of_fruits[2]

'orange'
In [32]:
tuple_of_fruits[2] = 'pineapple'

--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-32-a3e3c942490d> in <module> ----> 1 tuple_of_fruits[2] = 'pineapple' TypeError: 'tuple' object does not support item assignment 

### Tuple unpacking!

In [33]:
berries = ("strawberry", "blueberry", "raspberry")
berries

('strawberry', 'blueberry', 'raspberry')
In [34]:
berry0 = berries[0]
berry1 = berries[1]
berry2 = berries[2]
print("First berry: " + berry0)
print("Second berry: " + berry1)
print("Third berry: " + berry2)

First berry: strawberry Second berry: blueberry Third berry: raspberry
In [35]:
(b0, b1, b2) = berries
print("First berry: " + b0)
print("Second berry: " + b1)
print("Third berry: " + b2)

First berry: strawberry Second berry: blueberry Third berry: raspberry
In [36]:
(b0, b1) = berries

--------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-36-cb888c77e4ea> in <module> ----> 1 (b0, b1) = berries ValueError: too many values to unpack (expected 2) 

## Dictionaries

Dictionaries allow you to store values associated with some key. For example:

In [37]:
data = {
'response':'yes',
'response_time': 2.2350235982035,
'trial_number': 7
}

data

{'response': 'yes', 'response_time': 2.2350235982035, 'trial_number': 7}

Then, to access the values, you use square brackets (kind of like with lists):

In [38]:
data['response']

'yes'
In [39]:
data['response_time']

2.2350235982035
In [40]:
data['trial_number']

7

You can add something to a dictionary just by assigning to it:

In [41]:
data['correct_response'] = 'no'
data

{'response': 'yes', 'response_time': 2.2350235982035, 'trial_number': 7, 'correct_response': 'no'}
In [42]:
data['another_response']='yes'
data


{'response': 'yes', 'response_time': 2.2350235982035, 'trial_number': 7, 'correct_response': 'no', 'another_response': 'yes'}

Modifying dictionaries works similarly to lists:

In [44]:
data['trial_number'] = 8
data

{'response': 'yes', 'response_time': 2.2350235982035, 'trial_number': 8, 'correct_response': 'no', 'another_response': 'yes'}

# Control flow

## For loops

For loops have the following syntax:

for variable in iterable:
# you must indent 4 spaces (press tab to automatically indent)
# then write code here


where iterable is a list, tuple, dictionary, etc. that can be iterated over. On each iteration of the loop, variable will hold a different element of the iterable. On the first iteration, it will hold the first element of iterable, on the second iteration, it will hold the second element, and so on.

Printing out the numbers from 1 to 10:

In [45]:
for i in range(10):
print("The value of i is: " + str(i))

The value of i is: 0 The value of i is: 1 The value of i is: 2 The value of i is: 3 The value of i is: 4 The value of i is: 5 The value of i is: 6 The value of i is: 7 The value of i is: 8 The value of i is: 9
In [46]:
# this won't do anything!
for i in range(10):
i


Squaring the numbers from 1 to 10:

In [47]:
for i in range(10):
print(i ** 8)

0 1 256 6561 65536 390625 1679616 5764801 16777216 43046721

What if we want to construct a list of squares?

In [48]:
squares = []
for i in range(10):
squares.append(i ** 2)

squares


[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

We can also do this with list comprehensions, which are a shorthand for writing for loops:

In [49]:
squares = [i ** 2 for i in range(10)]
squares

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

## While loops

While loops aren't used as frequently in Python as they are in other languages, but they do exist. They have the form:

while condition:
# again, indent four spaces
# then write code here


where condition is an expression or variable that evaluates to a boolean (True or False).

In [50]:
i = 0
while i < 10:
print(i)
i = i + 1

0 1 2 3 4 5 6 7 8 9

## If statements

We don't want to always operate on every element of a list. Sometimes, we'd like to do different things, depending on the value of the item.

For example, this squares all even numbers and cubes all odd numbers:

In [51]:
squares_and_cubes = []
for i in range(10):
# i % 2 is "i modulo 2", and will be 0 if even, 1 if odd
if (i % 2) == 0:
squares_and_cubes.append(i ** 2)
else:
squares_and_cubes.append(i ** 3)

squares_and_cubes

[0, 1, 4, 27, 16, 125, 36, 343, 64, 729]

# Functions

Almost all the code you write for this class will be in functions -- this makes it easier for you to check your own work, and for us to grade it! Functions have the following form:

def function_name(argument1, argument2, argument3):
# indent four spaces
# write some code here
return something


where function_name is the name you want to call your function, and the variables inside the parentheses are the arguments to the function (you can have any number of arguments, including zero). The something that is returned should be defined within the function.

For example, here's a function that takes a list of numbers and squares it:

In [52]:
def make_squares(some_list):
new_list = []
for item in some_list:
new_list.append(item ** 2)
return new_list # this is very important -- don't forget the return statement!

In [53]:
make_squares([1, 2, 3])

[1, 4, 9]
In [54]:
another_list = [3, 9, 10, 24, 3, 234]
make_squares(another_list)

[9, 81, 100, 576, 9, 54756]

## Recursive functions

Functions can call themselves! This is a concept called recursion. For example, we can use recursion to compute the Fibonacci sequence:

In [55]:
def fibonacci(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
return fibonacci(n - 1) + fibonacci(n - 2)

In [70]:
fibonacci(2)

1
In [67]:
fibonacci(8)

21
In [71]:
fibonacci(10)

55

We can use functions in loops, too! For example, to get the first 10 Fibonacci numbers:

In [72]:
first_ten = []
for i in range(10):
first_ten.append(fibonacci(i))

first_ten

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
In [73]:
first_eleven = [fibonacci(i) for i in range(11)]