Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • HLI877/cs220-lecture-material
  • DANDAPANTULA/cs220-lecture-material
  • cdis/cs/courses/cs220/cs220-lecture-material
  • GIMOTEA/cs220-lecture-material
  • TWMILLER4/cs220-lecture-material
  • GU227/cs220-lecture-material
  • ABADAL/cs220-lecture-material
  • CMILTON3/cs220-lecture-material
  • BDONG39/cs220-lecture-material
  • JSANDOVAL6/cs220-lecture-material
  • JSABHARWAL2/cs220-lecture-material
  • GFREDERICKS/cs220-lecture-material
  • LMSUN/cs220-lecture-material
  • RBHALE/cs220-lecture-material
  • MILNARIK/cs220-lecture-material
  • SUTTI/cs220-lecture-material
  • NMISHRA4/cs220-lecture-material
  • HXIA36/cs220-lecture-material
  • DEPPELER/cs220-lecture-material
  • KIM2245/cs220-lecture-material
  • SKLEPFER/cs220-lecture-material
  • BANDIERA/cs220-lecture-material
  • JKILPS/cs220-lecture-material
  • SOERGEL/cs220-lecture-material
  • DBAUTISTA2/cs220-lecture-material
  • VLEFTWICH/cs220-lecture-material
  • MOU5/cs220-lecture-material
  • ALJACOBSON3/cs220-lecture-material
  • RCHOUDHARY5/cs220-lecture-material
  • MGERSCH/cs220-lecture-material
  • EKANDERSON8/cs220-lecture-material
  • ZHANG2752/cs220-lecture-material
  • VSANTAMARIA/cs220-lecture-material
  • VILBRANDT/cs220-lecture-material
  • ELADD2/cs220-lecture-material
  • YLIU2328/cs220-lecture-material
  • LMEASNER/cs220-lecture-material
  • ATANG28/cs220-lecture-material
  • AKSCHELLIN/cs220-lecture-material
  • OMBUSH/cs220-lecture-material
  • MJDAVID/cs220-lecture-material
  • AKHATRY/cs220-lecture-material
  • CZHUANG6/cs220-lecture-material
  • JPDEYOUNG/cs220-lecture-material
  • SDREES/cs220-lecture-material
  • CLCAMPBELL3/cs220-lecture-material
  • CJCAMPOS/cs220-lecture-material
  • AMARAN/cs220-lecture-material
  • rmflynn2/cs220-lecture-material
  • zhang2855/cs220-lecture-material
  • imanzoor/cs220-lecture-material
  • TOUSEEF/cs220-lecture-material
  • qchen445/cs220-lecture-material
  • nareed2/cs220-lecture-material
  • younkman/cs220-lecture-material
  • kli382/cs220-lecture-material
  • bsaulnier/cs220-lecture-material
  • isatrom/cs220-lecture-material
  • kgoodrum/cs220-lecture-material
  • mransom2/cs220-lecture-material
  • ahstevens/cs220-lecture-material
  • JRADUECHEL/cs220-lecture-material
  • mpcyr/cs220-lecture-material
  • wmeyrose/cs220-lecture-material
  • mmaltman/cs220-lecture-material
  • lsonntag/cs220-lecture-material
  • ghgallant/cs220-lecture-material
  • agkaiser2/cs220-lecture-material
  • rlgerhardt/cs220-lecture-material
  • chen2552/cs220-lecture-material
  • mickiewicz/cs220-lecture-material
  • cbarnish/cs220-lecture-material
  • alampson/cs220-lecture-material
  • mjwendt4/cs220-lecture-material
  • somsakhein/cs220-lecture-material
  • heppenibanez/cs220-lecture-material
  • szhang926/cs220-lecture-material
  • wewatson/cs220-lecture-material
  • jho34/cs220-lecture-material
  • lmedin/cs220-lecture-material
  • hjiang373/cs220-lecture-material
  • hfry2/cs220-lecture-material
  • ajroberts7/cs220-lecture-material
  • mcerhardt/cs220-lecture-material
  • njtomaszewsk/cs220-lecture-material
  • rwang728/cs220-lecture-material
  • jhansonflore/cs220-lecture-material
  • msajja/cs220-lecture-material
  • bjornson2/cs220-lecture-material
  • ccmclaren/cs220-lecture-material
  • armstrongbag/cs220-lecture-material
  • eloe2/cs220-lecture-material
92 results
Show changes
Showing
with 7753 additions and 0 deletions
{
"bob": [
20.0,
10.0
],
"alice": [
30.0,
20.0
],
"meena": [
100.0,
10.0
]
}
\ No newline at end of file
%% Cell type:markdown id: tags:
## Warmups
%% Cell type:code id: tags:
``` python
# Warmup 0: Recall how to read in and use json data
import json
# we are going to learn about this today !
from collections import namedtuple
# Deserialize
def read_json(path):
with open(path, encoding="utf-8") as f: # f is a variable
return json.load(f) # f represents a reference the JSON file
# Serialize
def write_json(path, data):
with open(path, 'w', encoding="utf-8") as f:
json.dump(data, f, indent=2)
kiva_dict = read_json('kiva.json')
loan_list = kiva_dict['data']['lend']['loans']['values'] # this gives us a list of dicts
loan_list[0].keys()
```
%% Output
dict_keys(['name', 'description', 'loanAmount', 'geocode'])
%% Cell type:code id: tags:
``` python
# Warmup 1a: What is the total amount needed to fund all of the loans?
tot_loan_amount = 0.0
for loan_dict in loan_list:
tot_loan_amount += float(loan_dict['loanAmount'])
tot_loan_amount
```
%% Output
4350.0
%% Cell type:code id: tags:
``` python
# Warmup 1b: What are the unique countries of origin in alphabetical order?
countries = []
for loan_dict in loan_list:
countries.append(loan_dict['geocode']['country']['name'])
uniq_countries = sorted(list(set(countries)))
uniq_countries
```
%% Output
['Albania', 'Kenya', 'Tajikistan', 'Togo']
%% Cell type:code id: tags:
``` python
# Warmup 2: Explain what the code below does
x = 1
```
%% Cell type:code id: tags:
``` python
# In Plain English: It assigns the value of 1 to x.
```
%% Cell type:markdown id: tags:
# CS220: Lecture 20
## Learning Objectives
After this lecture you will be able to...
- Explain the difference between objects vs references, and stack vs heap.
- Determine the side effects that occur when modifying parameters.
- Use tuples to store immutable sequences of values.
- Use namedtuple (immutable) to store user-defined data objects.
%% Cell type:markdown id: tags:
### Objects vs References & Stack vs Heap
- Check out the slides!
- Try some of the code in PythonTutor
%% Cell type:code id: tags:
``` python
# Warmup 2: Explain what the code below does
x = 1
```
%% Cell type:code id: tags:
``` python
# In Plain English: It assigns the value of 1 to x.
```
%% Cell type:code id: tags:
``` python
# More Precisely: It creates a reference variable, x, which refers to the object 1.
# Why? In Python, every variable is just a reference to an object.
# The variable only holds the memory address of the object it is referring to.
# The object is the actual data (e.g. an int, string, list, etc.)
#
# Think about it like a class roster.
# Each name on the roster refers to a student in the class.
# In this example, each name represents a variable, and each student represents an object.
```
%% Cell type:code id: tags:
``` python
# MOST Precisely: It creates a reference variable, x, stored on the stack
# which refers to the object 1, stored on the heap.
# Why? The heap is the collection of ALL objects. Think about it like a supermarket.
# The stack is the "stack" of frames we studied earlier in the semester.
# It is the ordered collection of function frames and their variables.
#
# Tip: Use PythonTutor to visualize this!
#
# Typically, the stack is much smaller in size than the heap.
#
```
%% Cell type:code id: tags:
``` python
# Warmup 2b: Explain what the code below does
shelf = ["sugar", "coffee"]
```
%% Cell type:code id: tags:
``` python
# In Plain English: It assigns a list of coffee and sugar to shelf.
```
%% Cell type:code id: tags:
``` python
# More Precisely: It creates a reference variable, shelf, stored on the stack which
# refers to a list of sugar and coffee on the heap.
```
%% Cell type:code id: tags:
``` python
# MOST Precisely: It creates a reference variable, shelf, stored on the stack which
# refers to a list object on the heap. This list object contains a
# reference to a string object "sugar" on the heap, followed by a
# reference to a string object "coffee" on the heap.
```
%% Cell type:markdown id: tags:
### Determine the side effects that occur when modifying parameters.
%% Cell type:markdown id: tags:
Example 1a [PythonTutor Link](https://pythontutor.com/visualize.html#code=def%20f%28x%29%3A%0A%20%20%20%20x%20*%3D%203%0A%20%20%20%20print%28%22f%3A%22,%20x%29%0A%0Anum%20%3D%2010%0Aprint%28%22before%3A%22,%20num%29%0Af%28num%29%0Aprint%28%22after%3A%22,%20num%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)
%% Cell type:code id: tags:
``` python
def f(x):
x *= 3
print("f:", x)
num = 10
print("before:", num)
f(num)
print("after:", num)
# Takeaway: What happens when a parameter is reassigned in a function?
# The original value does not change!
```
%% Output
before: 10
f: 30
after: 10
%% Cell type:markdown id: tags:
Example 1b, [PythonTutor Link](https://pythontutor.com/visualize.html#code=def%20f%28items%29%3A%0A%20%20%20%20items.append%28%22donuts%22%29%0A%20%20%20%20print%28%22f%3A%22,%20items%29%0A%0Awords%20%3D%20%5B'sugar',%20'coffee'%5D%0Aprint%28%22before%3A%22,%20words%29%0Af%28words%29%0Aprint%28%22after%3A%22,%20words%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)
%% Cell type:code id: tags:
``` python
def f(items):
items.append("donuts")
print("f:", items)
words = ['sugar', 'coffee']
print("before:", words)
f(words)
print("after:", words)
# Takeaway: What happens when a list parameter is mutated in a function?
# The list is changed! This is true for any mutable object.
```
%% Output
before: ['sugar', 'coffee']
f: ['sugar', 'coffee', 'donuts']
after: ['sugar', 'coffee', 'donuts']
%% Cell type:markdown id: tags:
Example 1c [PythonTutor Link](https://pythontutor.com/visualize.html#code=def%20f%28items%29%3A%0A%20%20%20%20items%20%3D%20items%20%2B%20%5B%22donuts%22%5D%0A%20%20%20%20print%28%22f%3A%22,%20items%29%0A%0Awords%20%3D%20%5B'sugar',%20'coffee'%5D%0Aprint%28%22before%3A%22,%20words%29%0Af%28words%29%0Aprint%28%22after%3A%22,%20words%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)
%% Cell type:code id: tags:
``` python
def f(items):
items = items + ["donuts"]
print("f:", items)
words = ['sugar', 'coffee']
print("before:", words)
f(words)
print("after:", words)
# Takeaway: What happens when a list parameter is reassigned?
# The original list is not changed.
```
%% Output
before: ['sugar', 'coffee']
f: ['sugar', 'coffee', 'donuts']
after: ['sugar', 'coffee']
%% Cell type:markdown id: tags:
Example 1d [PythonTutor Link](https://pythontutor.com/visualize.html#code=def%20first%28items%29%3A%0A%20%20%20%20return%20items%5B0%5D%0A%0Adef%20smallest%28items%29%3A%0A%20%20%20%20items.sort%28%29%0A%20%20%20%20return%20items%5B0%5D%0A%0Anumbers%20%3D%20%5B4,5,3,2,1%5D%0Aprint%28%22first%3A%22,%20first%28numbers%29%29%0Aprint%28%22smallest%3A%22,%20smallest%28numbers%29%29%0Aprint%28%22first%3A%22,%20first%28numbers%29%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)
%% Cell type:code id: tags:
``` python
def first(items):
return items[0]
def smallest(items):
items.sort()
return items[0]
numbers = [4,5,3,2,1]
print("first:", first(numbers))
print("smallest:", smallest(numbers))
print("first:", first(numbers))
# Takeaway: What happens when a list parameter is sorted "in place" using .sort() ?
# The original list is changed!
```
%% Output
first: 4
smallest: 1
first: 1
%% Cell type:markdown id: tags:
Example 1e [PythonTutor Link](https://pythontutor.com/visualize.html#code=def%20first%28items%29%3A%0A%20%20%20%20return%20items%5B0%5D%0A%0Adef%20smallest%28items%29%3A%0A%20%20%20%20items%20%3D%20sorted%28items%29%0A%20%20%20%20return%20items%5B0%5D%0A%0Anumbers%20%3D%20%5B4,5,3,2,1%5D%0Aprint%28%22first%3A%22,%20first%28numbers%29%29%0Aprint%28%22smallest%3A%22,%20smallest%28numbers%29%29%0Aprint%28%22first%3A%22,%20first%28numbers%29%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)
%% Cell type:code id: tags:
``` python
def first(items):
return items[0]
def smallest(items):
items = sorted(items)
return items[0]
numbers = [4,5,3,2,1]
print("first:", first(numbers))
print("smallest:", smallest(numbers))
print("first:", first(numbers))
# Takeaway: What happens when a list parameter is sorted using sorted()?
# The original list does not change.
```
%% Output
first: 4
smallest: 1
first: 4
%% Cell type:code id: tags:
``` python
# What can we say about the last two examples?
# sort() mutates the list; sorted does not mutate the list, it returns a new list.
```
%% Cell type:code id: tags:
``` python
# Write one good thing about lists being mutable:
# We can change (mutate) them in functions!
```
%% Cell type:code id: tags:
``` python
# Write one bad thing about lists being mutable:
# We can change (mutate) them in functions!
```
%% Cell type:markdown id: tags:
## Your Turn!
%% Cell type:markdown id: tags:
Explain how the below code works.
%% Cell type:code id: tags:
``` python
def add_vacation_plan(itinerary, location, plan):
# Itinerary is a dictionary of locations, where each location has a list of plans.
# We know that dictionaries and lists are mutable, so we can change them within this function.
#
# We first check if they have plans for the location, and if not start an empty list.
# Then, we add our plan onto the list of plans for that location.
if location not in itinerary:
itinerary[location] = []
itinerary[location].append(plan)
def get_vacation_plans(itinerary, location):
if location not in itinerary:
return []
return itinerary[location]
alices_vacay = {}
bobs_vacay = {}
add_vacation_plan(alices_vacay, "Malibu", "Swimming")
add_vacation_plan(alices_vacay, "San Diego", "Touring")
add_vacation_plan(alices_vacay, "San Diego", "Shopping")
add_vacation_plan(bobs_vacay, "Madison", "Studying")
add_vacation_plan(bobs_vacay, "HWY 151", "Driving")
add_vacation_plan(bobs_vacay, "Devils Lake", "Swimming")
add_vacation_plan(bobs_vacay, "Devils Lake", "Kayaking")
add_vacation_plan(bobs_vacay, "Devils Lake", "Hiking")
print(alices_vacay)
print(bobs_vacay)
print(get_vacation_plans(alices_vacay, 'San Diego'))
print(get_vacation_plans(bobs_vacay, 'Seattle'))
```
%% Output
{'Malibu': ['Swimming'], 'San Diego': ['Touring', 'Shopping']}
{'Madison': ['Studying'], 'HWY 151': ['Driving'], 'Devils Lake': ['Swimming', 'Kayaking', 'Hiking']}
['Touring', 'Shopping']
[]
%% Cell type:markdown id: tags:
### Use tuples to store immutable sequences of values.
Check out the slides about tuples
%% Cell type:code id: tags:
``` python
# Tuples are like lists BUT are IMMUTABLE
# practice with tuples
scores = [32, 55, 72, 91] # a list is mutable
coordinates = (-3, 4, 7) # a tuple is not mutable
```
%% Cell type:code id: tags:
``` python
# show that scores is mutable
scores[-1] = 100
print(scores)
# show that tuples are immutable
#coordinates[-1] = 100. #tuple not mutable
#print(coordinates)
```
%% Output
[32, 55, 72, 100]
%% Cell type:code id: tags:
``` python
coordinates = (5, 77, -3) # However, re-assignment is OK
print(coordinates)
```
%% Output
(5, 77, -3)
%% Cell type:code id: tags:
``` python
scores_tuple = tuple(scores) # you can convert a list into a tuple
print(scores_tuple)
```
%% Output
(32, 55, 72, 100)
%% Cell type:code id: tags:
``` python
# Question: Can tuples be sorted?
# Discuss with your neighbor
# coordinates.sort() # tuples are immutable
new_tuple = sorted(coordinates) # sorted makes a new object
```
%% Cell type:code id: tags:
``` python
# reference: https://www.w3schools.com/python/python_tuples.asp
```
%% Cell type:code id: tags:
``` python
# Why use tuples?
# keys in dictionaries must be immutable types
# some data never changes : GPS coordinates
# Fails with TypeError
buildings = {
[0,0]: "Comp Sci",
[0,2]: "Psychology",
[4,0]: "Noland",
[1,8]: "Van Vleck" }
```
%% Output
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[29], line 6
1 # Why use tuples?
2 # keys in dictionaries must be immutable types
3 # some data never changes : GPS coordinates
4
5 # Fails with TypeError
----> 6 buildings = {
7 [0,0]: "Comp Sci",
8 [0,2]: "Psychology",
9 [4,0]: "Noland",
10 [1,8]: "Van Vleck" }
TypeError: unhashable type: 'list'
%% Cell type:code id: tags:
``` python
# Works with tuple as keys
buildings = {
(0,0): "Comp Sci",
(0,2): "Psychology",
(4,0): "Noland",
(1,8): "Van Vleck" }
# find the name of the building at coordinate (4,0)
buildings[(4,0)]
```
%% Output
'Noland'
%% Cell type:markdown id: tags:
### 21.3 Use namedtuple (immutable) to store user-defined data objects.
- namedtuple is useful for creating well-defined objects
- namedtuple is like a mix of tuples and dictionaries
- let's look at the slides
%% Cell type:code id: tags:
``` python
people = []
# A namedtuple is like its own kind of type!
# its a Python convention to use a Capital letter when naming a namedtuple
# define a namedtuple called Person
Person = namedtuple("Person", ["fname", "lname", "age"])
# make a single person....please don't name it person !!
p1 = Person("Bucky", "Badger", 124)
print(p1.age)
# Add another Person by using keyword arguments
person2 = Person(age=25, lname="Star", fname = "Patrick")
```
%% Output
124
%% Cell type:code id: tags:
``` python
# make a list of Persons
people=[
Person("Alice", "Anderson", 30), # positional arguments
Person("Bob", "Baker", 31),
# add two more Persons to people
Person("Celia", "Answer", 21),
Person("Marcus", "Carlson", 33)
]
# Print the first person's name.
person0 = people[0]
print("Hello " + person0.fname + " " + person0.lname)
```
%% Output
Hello Alice Anderson
%% Cell type:code id: tags:
``` python
# Print out everyone's name!
print(people)
for p in people:
print("Hello " + p.fname + " " + p.lname)
```
%% Output
[Person(fname='Alice', lname='Anderson', age=30), Person(fname='Bob', lname='Baker', age=31), Person(fname='Celia', lname='Answer', age=21), Person(fname='Marcus', lname='Carlson', age=33)]
Hello Alice Anderson
Hello Bob Baker
Hello Celia Answer
Hello Marcus Carlson
%% Cell type:markdown id: tags:
Namedtuples have a deeper significance....the namedtuples we create are their own type
%% Cell type:markdown id: tags:
![namedtuple.png](attachment:namedtuple.png)
%% Cell type:code id: tags:
``` python
# Write a function to find the average age of the Persons in people
def avg_age(p_list):
# assume p_list is a list of Persons
sum_ages = 0
for person in p_list:
sum_ages += person.age
return sum_ages / len(p_list)
avg_age(people)
```
%% Output
28.75
%% Cell type:code id: tags:
``` python
```
%% Cell type:markdown id: tags:
## Warmups
%% Cell type:code id: tags:
``` python
# Warmup 0: Recall how to read in and use json data
import json
# we are going to learn about this today !
from collections import namedtuple
# Deserialize
def read_json(path):
with open(path, encoding="utf-8") as f: # f is a variable
return json.load(f) # f represents a reference the JSON file
# Serialize
def write_json(path, data):
with open(path, 'w', encoding="utf-8") as f:
json.dump(data, f, indent=2)
kiva_dict = read_json('kiva.json')
loan_list = kiva_dict['data']['lend']['loans']['values'] # this gives us a list of dicts
loan_list[0].keys()
```
%% Cell type:code id: tags:
``` python
# Warmup 1a: What is the total amount needed to fund all of the loans?
```
%% Cell type:code id: tags:
``` python
# Warmup 1b: What are the unique countries of origin in alphabetical order?
```
%% Cell type:code id: tags:
``` python
# Warmup 2: Explain what the code below does
x = 1
```
%% Cell type:markdown id: tags:
# CS220: Lecture 20
## Learning Objectives
After this lecture you will be able to...
- Explain the difference between objects vs references, and stack vs heap.
- Determine the side effects that occur when modifying parameters.
- Use tuples to store immutable sequences of values.
- Use namedtuple (immutable) to store user-defined data objects.
%% Cell type:markdown id: tags:
### Objects vs References & Stack vs Heap
- Check out the slides!
- Try some of the code in PythonTutor
%% Cell type:code id: tags:
``` python
# Warmup 2: Explain what the code below does
x = 1
```
%% Cell type:code id: tags:
``` python
# Warmup 2b: Explain what the code below does
shelf = ["sugar", "coffee"]
```
%% Cell type:markdown id: tags:
### Determine the side effects that occur when modifying parameters.
%% Cell type:markdown id: tags:
Example 1a [PythonTutor Link](https://pythontutor.com/visualize.html#code=def%20f%28x%29%3A%0A%20%20%20%20x%20*%3D%203%0A%20%20%20%20print%28%22f%3A%22,%20x%29%0A%0Anum%20%3D%2010%0Aprint%28%22before%3A%22,%20num%29%0Af%28num%29%0Aprint%28%22after%3A%22,%20num%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)
%% Cell type:code id: tags:
``` python
def f(x):
x *= 3
print("f:", x)
num = 10
print("before:", num)
f(num)
print("after:", num)
# Takeaway: What happens when a parameter is reassigned in a function?
```
%% Output
before: 10
f: 30
after: 10
%% Cell type:markdown id: tags:
Example 1b, [PythonTutor Link](https://pythontutor.com/visualize.html#code=def%20f%28items%29%3A%0A%20%20%20%20items.append%28%22donuts%22%29%0A%20%20%20%20print%28%22f%3A%22,%20items%29%0A%0Awords%20%3D%20%5B'sugar',%20'coffee'%5D%0Aprint%28%22before%3A%22,%20words%29%0Af%28words%29%0Aprint%28%22after%3A%22,%20words%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)
%% Cell type:code id: tags:
``` python
def f(items):
items.append("donuts")
print("f:", items)
words = ['sugar', 'coffee']
print("before:", words)
f(words)
print("after:", words)
# Takeaway: What happens when a list parameter is mutated in a function?
```
%% Output
before: ['sugar', 'coffee']
f: ['sugar', 'coffee', 'donuts']
after: ['sugar', 'coffee', 'donuts']
%% Cell type:markdown id: tags:
Example 1c [PythonTutor Link](https://pythontutor.com/visualize.html#code=def%20f%28items%29%3A%0A%20%20%20%20items%20%3D%20items%20%2B%20%5B%22donuts%22%5D%0A%20%20%20%20print%28%22f%3A%22,%20items%29%0A%0Awords%20%3D%20%5B'sugar',%20'coffee'%5D%0Aprint%28%22before%3A%22,%20words%29%0Af%28words%29%0Aprint%28%22after%3A%22,%20words%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)
%% Cell type:code id: tags:
``` python
def f(items):
items = items + ["donuts"]
print("f:", items)
words = ['sugar', 'coffee']
print("before:", words)
f(words)
print("after:", words)
# Takeaway: What happens when a list parameter is reassigned?
```
%% Output
before: ['sugar', 'coffee']
f: ['sugar', 'coffee', 'donuts']
after: ['sugar', 'coffee']
%% Cell type:markdown id: tags:
Example 1d [PythonTutor Link](https://pythontutor.com/visualize.html#code=def%20first%28items%29%3A%0A%20%20%20%20return%20items%5B0%5D%0A%0Adef%20smallest%28items%29%3A%0A%20%20%20%20items.sort%28%29%0A%20%20%20%20return%20items%5B0%5D%0A%0Anumbers%20%3D%20%5B4,5,3,2,1%5D%0Aprint%28%22first%3A%22,%20first%28numbers%29%29%0Aprint%28%22smallest%3A%22,%20smallest%28numbers%29%29%0Aprint%28%22first%3A%22,%20first%28numbers%29%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)
%% Cell type:code id: tags:
``` python
def first(items):
return items[0]
def smallest(items):
items.sort()
return items[0]
numbers = [4,5,3,2,1]
print("first:", first(numbers))
print("smallest:", smallest(numbers))
print("first:", first(numbers))
# Takeaway: What happens when a list parameter is sorted "in place" using .sort() ?
```
%% Output
first: 4
smallest: 1
first: 1
%% Cell type:markdown id: tags:
Example 1e [PythonTutor Link](https://pythontutor.com/visualize.html#code=def%20first%28items%29%3A%0A%20%20%20%20return%20items%5B0%5D%0A%0Adef%20smallest%28items%29%3A%0A%20%20%20%20items%20%3D%20sorted%28items%29%0A%20%20%20%20return%20items%5B0%5D%0A%0Anumbers%20%3D%20%5B4,5,3,2,1%5D%0Aprint%28%22first%3A%22,%20first%28numbers%29%29%0Aprint%28%22smallest%3A%22,%20smallest%28numbers%29%29%0Aprint%28%22first%3A%22,%20first%28numbers%29%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)
%% Cell type:code id: tags:
``` python
def first(items):
return items[0]
def smallest(items):
items = sorted(items)
return items[0]
numbers = [4,5,3,2,1]
print("first:", first(numbers))
print("smallest:", smallest(numbers))
print("first:", first(numbers))
# Takeaway: What happens when a list parameter is sorted using sorted()?
```
%% Output
first: 4
smallest: 1
first: 4
%% Cell type:code id: tags:
``` python
# What can we say about the last two examples?
```
%% Cell type:code id: tags:
``` python
# Write one good thing about lists being mutable:
```
%% Cell type:code id: tags:
``` python
# Write one bad thing about lists being mutable:
```
%% Cell type:markdown id: tags:
## Your Turn!
%% Cell type:markdown id: tags:
Explain how the below code works.
%% Cell type:code id: tags:
``` python
def add_vacation_plan(itinerary, location, plan):
if location not in itinerary:
itinerary[location] = []
itinerary[location].append(plan)
def get_vacation_plans(itinerary, location):
if location not in itinerary:
return []
return itinerary[location]
alices_vacay = {}
bobs_vacay = {}
add_vacation_plan(alices_vacay, "Malibu", "Swimming")
add_vacation_plan(alices_vacay, "San Diego", "Touring")
add_vacation_plan(alices_vacay, "San Diego", "Shopping")
add_vacation_plan(bobs_vacay, "Madison", "Studying")
add_vacation_plan(bobs_vacay, "HWY 151", "Driving")
add_vacation_plan(bobs_vacay, "Devils Lake", "Swimming")
add_vacation_plan(bobs_vacay, "Devils Lake", "Kayaking")
add_vacation_plan(bobs_vacay, "Devils Lake", "Hiking")
print(alices_vacay)
print(bobs_vacay)
print(get_vacation_plans(alices_vacay, 'San Diego'))
print(get_vacation_plans(bobs_vacay, 'Seattle'))
```
%% Output
{'Malibu': ['Swimming'], 'San Diego': ['Touring', 'Shopping']}
{'Madison': ['Studying'], 'HWY 151': ['Driving'], 'Devils Lake': ['Swimming', 'Kayaking', 'Hiking']}
['Touring', 'Shopping']
[]
%% Cell type:markdown id: tags:
### Use tuples to store immutable sequences of values.
Check out the slides about tuples
%% Cell type:code id: tags:
``` python
# Tuples are like lists BUT are IMMUTABLE
# practice with tuples
scores = [32, 55, 72, 91] # a list is mutable
coordinates = (-3, 4, 7) # a tuple is not mutable
```
%% Cell type:code id: tags:
``` python
# show that scores is mutable
scores[-1] = 100
print(scores)
# show that tuples are immutable
#coordinates[-1] = 100. #tuple not mutable
#print(coordinates)
```
%% Output
[32, 55, 72, 100]
%% Cell type:code id: tags:
``` python
coordinates = (5, 77, -3) # However, re-assignment is OK
print(coordinates)
```
%% Output
(5, 77, -3)
%% Cell type:code id: tags:
``` python
scores_tuple = tuple(scores) # you can convert a list into a tuple
print(scores_tuple)
```
%% Output
(32, 55, 72, 100)
%% Cell type:code id: tags:
``` python
# Question: Can tuples be sorted?
# Discuss with your neighbor
```
%% Cell type:code id: tags:
``` python
# reference: https://www.w3schools.com/python/python_tuples.asp
```
%% Cell type:code id: tags:
``` python
# Why use tuples?
# keys in dictionaries must be immutable types
# some data never changes : GPS coordinates
# Fails with TypeError
buildings = {
[0,0]: "Comp Sci",
[0,2]: "Psychology",
[4,0]: "Noland",
[1,8]: "Van Vleck" }
```
%% Output
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
C:\Users\COLENE~1\AppData\Local\Temp/ipykernel_18196/3672081683.py in <module>
4
5 # Fails with TypeError
----> 6 buildings = {
7 [0,0]: "Comp Sci",
8 [0,2]: "Psychology",
TypeError: unhashable type: 'list'
%% Cell type:code id: tags:
``` python
# Works with tuple as keys
buildings = {
(0,0): "Comp Sci",
(0,2): "Psychology",
(4,0): "Noland",
(1,8): "Van Vleck" }
# find the name of the building at coordinate (4,0)
```
%% Output
'Noland'
%% Cell type:markdown id: tags:
### 21.3 Use namedtuple (immutable) to store user-defined data objects.
- namedtuple is useful for creating well-defined objects
- namedtuple is like a mix of tuples and dictionaries
- let's look at the slides
%% Cell type:code id: tags:
``` python
people = []
# A namedtuple is like its own kind of type!
# its a Python convention to use a Capital letter when naming a namedtuple
# define a namedtuple called Person
Person = namedtuple("Person", ["fname", "lname", "age"])
# make a single person....please don't name it person !!
# Add another Person by using keyword arguments
```
%% Output
124
%% Cell type:code id: tags:
``` python
# make a list of Persons
people=[
Person("Alice", "Anderson", 30), # positional arguments
Person("Bob", "Baker", 31),
# add two more Persons to people
Person("Celia", "Answer", 21),
Person("Marcus", "Carlson", 33)
]
# Print the first person's name.
```
%% Output
Hello Alice Anderson
%% Cell type:code id: tags:
``` python
# Print out everyone's name!
```
%% Output
[Person(fname='Alice', lname='Anderson', age=30), Person(fname='Bob', lname='Baker', age=31), Person(fname='Celia', lname='Answer', age=21), Person(fname='Marcus', lname='Carlson', age=33)]
Hello Alice Anderson
Hello Bob Baker
Hello Celia Answer
Hello Marcus Carlson
%% Cell type:markdown id: tags:
Namedtuples have a deeper significance....the namedtuples we create are their own type
%% Cell type:markdown id: tags:
![namedtuple.png](attachment:namedtuple.png)
%% Cell type:code id: tags:
``` python
# Write a function to find the average age of the Persons in people
def avg_age(p_list):
# assume p_list is a list of Persons
pass
avg_age(people)
```
%% Output
28.75
{
"data": {
"lend": {
"loans": {
"values": [
{
"name": "Polikseni",
"description": "Polikseni is 70 years old and married. She and her husband are both retired and their main income is a retirement pension of $106 a month for Polikseni and disability income for her husband of $289 a month. <br /><br />Polikseni's husband, even though disabled, works in a very small shop as a watchmaker on short hours, just to provide additional income for his family and to feel useful. Polikseni's husband needs constant medical treatment due to his health problems. She requested another loan, which she will use to continue paying for the therapy her husband needs. With a part of the loan, she is going to pay the remainder of the previous loan.",
"loanAmount": "1325.00",
"geocode": {
"city": "Korce",
"country": {
"name": "Albania",
"region": "Eastern Europe",
"fundsLentInCountry": 9051250
}
}
},
{
"name": "Safarmo",
"description": "Safarmo is 47 years old. She lives with her husband and her children in Khuroson district. <br /><br />Safarmo is a seamstress. She has been engaged in sewing for 10 years. She learned this activity with help of her mother and elder sister. <br /><br />Safarmo's sewing machine is old and she cannot work well. Her difficulty is lack of money. That’s why she applied for a loan to buy a new modern sewing machine. <br /><br />Safarmo needs your support.",
"loanAmount": "1075.00",
"geocode": {
"city": "Khuroson",
"country": {
"name": "Tajikistan",
"region": "Asia",
"fundsLentInCountry": 64243075
}
}
},
{
"name": "Elizabeth",
"description": "Elizabeth is a mom blessed with five lovely children, who are her greatest motivation in life. She lives in the Natuu area of Kenya. Elizabeth is one of the most hardworking women in sub-Saharan Africa. Being a mother and living in a poor country has never been an excuse for Elizabeth, who has practiced mixed farming for the past few years.<br /><br />The cultural expectations in her area contribute to the notion that men should support their families. However, Elizabeth works independently for the success of her children. She perseveres because she wants to provide a better future for them.<br /><br />Elizabeth has always loved farming. She is a very proud farmer and enjoys milking her dairy cows. Elizabeth keeps poultry and grows crops, but she has not been making a good profit because of poor farming inputs. <br /><br />Elizabeth will use this loan to buy farm inputs and purchase high-quality seeds and good fertilizer to improve her crop production. Modern farming requires the use of modern techniques, and, therefore, using high-quality seeds will assure her of a bumper harvest and increased profit levels.<br /><br />Elizabeth is very visionary. Her goal for the season is to boost her crop production over the previous year.",
"loanAmount": "800.00",
"geocode": {
"city": "Matuu",
"country": {
"name": "Kenya",
"region": "Africa",
"fundsLentInCountry": 120841775
}
}
},
{
"name": "Ester",
"description": "Ester believes that this year is her year of prosperity. Ester is a hardworking, progressive and honest farmer from a very remote village in the Kitale area of Kenya. This area is very fertile, with favorable weather patterns that support farming activities. Ester is happily married and the proud mother of lovely children. Together, they live on a small piece of land that she really treasures. Her primary sources of income are eggs and milk.<br /><br />Although this humble and industrious mother makes a profit, she faces the challenge of not being able to produce enough to meet the readily available market. Therefore, she is seeking funds from Kiva lenders to buy farm inputs such as good fertilizer and good-quality seeds. Through this loan, Ester should double her production, and this will translate into increased income. She then intends to save more money in the future so that she can develop her farming.<br /><br />One objective that Juhudi Kilimo aims at fulfilling is increasing the ease of accessing farm inputs and income-generating assets for farmers. Through the intervention of Juhudi Kilimo and Kiva, inputs such as fertilizers and pesticides have become more accessible to its members than buying a bottle of water. Ester is very optimistic and believes this loan will change her life completely.",
"loanAmount": "275.00",
"geocode": {
"city": "Kitale",
"country": {
"name": "Kenya",
"region": "Africa",
"fundsLentInCountry": 120841775
}
}
},
{
"name": "Cherifa",
"description": "Cherifa is married, 57 years old with two children. She caters and also sells the local drink. She asks for credit to buy the necessities, in particular bags of anchovies, bags of maize and bundles of firewood. She wants to have enough income to run the house well.",
"loanAmount": "875.00",
"geocode": {
"city": "Agoe",
"country": {
"name": "Togo",
"region": "Africa",
"fundsLentInCountry": 13719125
}
}
}
]
}
}
}
}
\ No newline at end of file
Source diff could not be displayed: it is too large. Options to address this: view the blob.
Source diff could not be displayed: it is too large. Options to address this: view the blob.
%% Cell type:markdown id:193622e7 tags:
**Q2:** [PythonTutor Link](https://pythontutor.com/visualize.html#code=x%20%3D%20%5B1,%202,%203%5D%0Ay%20%3D%20%5B1,%202,%203%5D%0Az%20%3D%20x%0Az.append%284%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)
%% Cell type:code id:131b9746 tags:
``` python
x = [1, 2, 3]
y = [1, 2, 3]
z = x
z.append(4)
```
%% Cell type:markdown id:f578b492 tags:
**Q3:** [PythonTutor Link](https://pythontutor.com/visualize.html#code=nums1%20%3D%20%5B1,2%5D%0Anums2%20%3D%20nums1%0Ax%20%3D%20nums2.pop%281%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)
%% Cell type:code id:6d6a052b tags:
``` python
nums1 = [1,2]
nums2 = nums1
x = nums2.pop(1)
```
%% Cell type:markdown id:0abc64c0 tags:
**Q4:** [PythonTutor Link](https://pythontutor.com/visualize.html#code=x%20%3D%20%5B1,%202%5D%0Ay%20%3D%20%5B3%5D%0Az%20%3D%20x%20%2B%20y%0Ay.append%284%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)
%% Cell type:code id:373369b9 tags:
``` python
x = [1, 2]
y = [3]
z = x + y
y.append(4)
```
%% Cell type:markdown id:a3eb791e tags:
**Q5:** [PythonTutor Link](https://pythontutor.com/visualize.html#code=people%20%3D%20%7B%22alice%22%3A30,%20%22bob%22%3A25%7D%0Ax%20%3D%20people%0Ay%20%3D%20people%5B%22bob%22%5D%0Ax%5B%22alice%22%5D%20%3D%2031%0Ay%20%3D%2026&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)
%% Cell type:code id:ab703ab8 tags:
``` python
people = {"alice":30, "bob":25}
x = people
y = people["bob"]
x["alice"] = 31
y = 26
```
%% Cell type:markdown id:6dd6f676 tags:
**Q6:** [PythonTutor Link](https://pythontutor.com/visualize.html#code=def%20f%28items%29%3A%0A%20%20%20%20return%20items.pop%280%29%0Anums%20%3D%20%5B1,2,3%5D%0Anums.append%28f%28nums%29%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)
%% Cell type:code id:81a7d6d6 tags:
``` python
def f(items):
return items.pop(0)
nums = [1,2,3]
nums.append(f(nums))
```
%% Cell type:markdown id:5cea38e0 tags:
**Q7 (As Written):** [PythonTutor Link](https://pythontutor.com/visualize.html#code=import%20copy%0Ax%20%3D%20%5B2,1%5D%0Ay%20%3D%20copy.copy%28y%29%0Ay.sort%28%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)
%% Cell type:code id:ed06d8b5 tags:
``` python
import copy
x = [2,1]
y = copy.copy(y)
y.sort()
```
%% Cell type:markdown id:1499a535 tags:
**Q7 (As Fixed):** [PythonTutor Link](https://pythontutor.com/visualize.html#code=import%20copy%0Ax%20%3D%20%5B2,1%5D%0Ay%20%3D%20copy.copy%28x%29%0Ay.sort%28%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)
%% Cell type:code id:25a014f1 tags:
``` python
import copy
x = [2,1]
y = copy.copy(x)
y.sort()
```
%% Cell type:markdown id:88899380 tags:
**Q8:** [PythonTutor Link](https://pythontutor.com/visualize.html#code=import%20copy%0Adef%20biggest%28items%29%3A%0A%20%20%20%20items%20%3D%20copy.copy%28items%29%0A%20%20%20%20items.sort%28%29%0A%20%20%20%20return%20items%5B-1%5D%0Anums%20%3D%20%5B3,9,6%5D%0Ax%20%3D%20biggest%28nums%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)
%% Cell type:code id:a03f0f27 tags:
``` python
import copy
def biggest(items):
items = copy.copy(items)
items.sort()
return items[-1]
nums = [3,9,6]
x = biggest(nums)
```
%% Cell type:markdown id:60f15a79 tags:
**Q9:** [PythonTutor Link](https://pythontutor.com/visualize.html#code=import%20copy%0Ateam1%20%3D%20%5B%0A%20%20%7B%22name%22%3A%22A%22,%20%22age%22%3A7%7D%0A%5D%0Ateam2%20%3D%20copy.copy%28team1%29%0Ateam2.append%28%0A%20%20%7B%22name%22%3A%22B%22,%20%22age%22%3A9%7D%0A%29%0Ateam2%5B0%5D%5B%22age%22%5D%20%3D%208%0Ax%20%3D%20team1%5B0%5D%5B%22age%22%5D&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)
%% Cell type:code id:ba913d5b tags:
``` python
import copy
team1 = [
{"name":"A", "age":7}
]
team2 = copy.copy(team1)
team2.append(
{"name":"B", "age":9}
)
team2[0]["age"] = 8
x = team1[0]["age"]
```
%% Cell type:markdown id:9e3d7dd3 tags:
**Q10:** [PythonTutor Link](https://pythontutor.com/visualize.html#code=import%20copy%0Ateam1%20%3D%20%5B%0A%20%20%7B%22name%22%3A%22A%22,%20%22age%22%3A7%7D%0A%5D%0Ateam2%20%3D%20copy.deepcopy%28team1%29%0Ateam2.append%28%0A%20%20%7B%22name%22%3A%22B%22,%20%22age%22%3A9%7D%0A%29%0Ateam2%5B0%5D%5B%22age%22%5D%20%3D%208%0Ax%20%3D%20team1%5B0%5D%5B%22age%22%5D&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)
%% Cell type:code id:1c49cbcb tags:
``` python
import copy
team1 = [
{"name":"A", "age":7}
]
team2 = copy.deepcopy(team1)
team2.append(
{"name":"B", "age":9}
)
team2[0]["age"] = 8
x = team1[0]["age"]
```
%% Cell type:markdown id:30953821 tags:
**Q11:** [PythonTutor Link](https://pythontutor.com/visualize.html#code=import%20copy%0Aorig%20%3D%20%5B1,%5B2,%5B3,4%5D%5D%5D%0Ax%20%3D%20orig%0Ay%20%3D%20copy.copy%28orig%29%0Az%20%3D%20copy.deepcopy%28orig%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)
%% Cell type:code id:e67ede97 tags:
``` python
import copy
orig = [1,[2,[3,4]]]
x = orig
y = copy.copy(orig)
z = copy.deepcopy(orig)
```
%% Cell type:code id: tags:
``` python
# Warmup 0: What is the difference between these two pieces of code?
# In the first example, we create a new grocery dictionary for each grocery
# In the second example, we only create a new grocery dictionary once
# (before the loop starts) and overwrite it on each iteration
```
%% Cell type:code id: tags:
``` python
groceries = ["apples", "bananas", "coconuts", "dragonfruit"]
groceries_dicts = []
for grocery in groceries:
grocery_dict = {}
grocery_dict['name'] = grocery
grocery_dict['size'] = len(grocery)
groceries_dicts.append(grocery_dict)
groceries_dicts
```
%% Output
[{'name': 'apples', 'size': 6},
{'name': 'bananas', 'size': 7},
{'name': 'coconuts', 'size': 8},
{'name': 'dragonfruit', 'size': 11}]
%% Cell type:code id: tags:
``` python
groceries = ["apples", "bananas", "coconuts", "dragonfruit"]
groceries_dicts = []
grocery_dict = {}
for grocery in groceries:
grocery_dict['name'] = grocery
grocery_dict['size'] = len(grocery)
groceries_dicts.append(grocery_dict)
groceries_dicts
```
%% Output
[{'name': 'dragonfruit', 'size': 11},
{'name': 'dragonfruit', 'size': 11},
{'name': 'dragonfruit', 'size': 11},
{'name': 'dragonfruit', 'size': 11}]
%% Cell type:code id: tags:
``` python
# Let's use PythonTutor to investigate!
```
%% Cell type:code id: tags:
``` python
# Warmup 1a: Use 'in' to determine if something is in my_list
my_list = ["meet", "me", "after", 84]
print("me" in my_list)
print(84 in my_list)
```
%% Output
True
True
%% Cell type:code id: tags:
``` python
# Warmup 1b: What about this list?
my_list = [11, "meet", ["me", "them", "us"], [84,19, 22], "school", 2.54]
print("meet" in my_list)
print(84 in my_list)
```
%% Output
True
False
%% Cell type:code id: tags:
``` python
# Warmup 2a: Write a function to find a thing in a list that may have lists in it
my_list = [11, "meet", ["me", "them", "us"], [84,19, 22], "school", 2.54]
def search_list_depth2(target, some_list):
''' returns True if thing in some_list, False otherwise'''
for list_item in some_list:
if target == list_item:
return True
elif type(list_item) == list and target in list_item:
return True
return False # after all possible searching....not found
print(search_list_depth2("school", my_list)) # in list
print(search_list_depth2(22, my_list)) # in nested list
print(search_list_depth2("house", my_list)) # not anywhere
```
%% Output
True
True
False
%% Cell type:code id: tags:
``` python
# Warmup 2b: Will our function work on this list? Guess:
list_3_deep = [22, [33, 44, [55, 66], 77 ], 88]
# let's try it with our previous function
print(search_list_depth2(22, list_3_deep)) # in list
print(search_list_depth2(99, list_3_deep)) # not in list
# Write other tests to be sure that it works
print(search_list_depth2(33, list_3_deep)) # in nested list
print(search_list_depth2(55, list_3_deep)) # in nested nested list
```
%% Output
True
False
True
False
%% Cell type:code id: tags:
``` python
# Warmup 2c: What about ANY depth list?
# That is the goal of today's lecture
list_3_deep = [22, [33, 44, [55, 66], 77 ], 88]
def search_list_depth_any(target, some_list):
''' returns True if thing in some_list, False otherwise'''
for list_item in some_list:
if target == list_item:
return True
elif type(list_item) == list:
is_in_next = search_list_depth_any(target, list_item)
if is_in_next:
return True
return False # after all possible searching....not found
search_list_depth_any(55, list_3_deep)
```
%% Output
True
%% Cell type:markdown id: tags:
### Lecture 22: Recursion
After today's Lecture you will be able to:
Define recursion and be able to identify
- the base case
- the recursive case
- infinite recursion
Explain why the following can be recursively defined
- lists
- dictionaries
Trace a recursive function
- involving numeric computation
- involving nested data structures
%% Cell type:markdown id: tags:
## What is Recursion?
Recursion is defined as the process of defining something in terms of itself.
%% Cell type:markdown id: tags:
![image.png](attachment:image.png)
%% Cell type:markdown id: tags:
### Define recursion and be able to identify
- the base case
- the recursive case
- infinite recursion
%% Cell type:code id: tags:
``` python
# In math, you can define the factorial of a number in terms of the number before it.
# Q: What is the value of 84!
# A: 84 * 83!
# What are we still missing?
# A: 0! = 1
```
%% Cell type:markdown id: tags:
### A recursive algorithm must have 2 parts:
- the base case....which stops the recursion
- the recursive case...which defines the same process in a smaller way
#### If there is no base case what happens in the above example?
- recursion never ends......infinite recursion
- infinite recursion can also happen if the recursive case does not move towards the base
%% Cell type:markdown id: tags:
### Writing Definitions Recursively
%% Cell type:code id: tags:
``` python
# Define the sequence 1, 3, 5, 7, 9, 11... recursively
# Base Case: seq_0 = 1
# Recursive Case: seq_n = seq_(n - 1) + 2
```
%% Cell type:code id: tags:
``` python
# Define whether a positive number is odd recursively
# Base Case: 1 is odd
# Recursive Case: True if (n - 2) is odd, False otherwise
```
%% Cell type:markdown id: tags:
### Writing Recursive Code
%% Cell type:code id: tags:
``` python
def factorial(n):
if n == 0:
return 1
else:
return n * factorial(n - 1)
print(factorial(0))
print(factorial(3))
print(factorial(6))
```
%% Output
1
6
720
%% Cell type:markdown id: tags:
### Write and try `is_odd` in PythonTutor
%% Cell type:code id: tags:
``` python
def is_odd(n):
if n == 1:
return True
elif n == 0:
return False
else:
if n < 0:
return is_odd(n + 2)
else:
return is_odd(n - 2)
is_odd(-3)
```
%% Output
True
%% Cell type:markdown id: tags:
### Can we write them iteratively instead?
%% Cell type:code id: tags:
``` python
def factorial_itr(n):
prod = 1
for i in range(1, n + 1):
prod *= i
return prod
print(factorial_itr(0))
print(factorial_itr(3))
print(factorial_itr(6))
```
%% Output
1
6
720
%% Cell type:markdown id: tags:
### Other Recursive Problems
Go back and complete Warmup 2.C
%% Cell type:code id: tags:
``` python
# The Collatz Conjecture problem
# Conjecture: Any positive integer n, put through the below equation
# will always converge to 1.
#
# https://en.wikipedia.org/wiki/Collatz_conjecture
# https://www.youtube.com/watch?v=5mFpVDpKX70
# US$500 for solving. And likely an honorary doctorate.
# Run this in Python Tutor on your own
def collatz(n):
print(n)
if n == 1:
return 1 # base case
elif n % 2 == 0:
return collatz(n//2)
else:
return collatz (3*n+1)
collatz(13) # try other numbers
```
%% Output
13
40
20
10
5
16
8
4
2
1
1
%% Cell type:markdown id: tags:
### Trace a recursive function involving nested data structures
%% Cell type:code id: tags:
``` python
# example 4
fav_stuff = [ "road bike",
["PB&J", "brownies", "spaghetti", "apples"] ,
("Brooks Ghost 13", "hoodie", "gloves"),
"macbook air",
[ "Johndee.com", "https://www.weather.gov/mkx/"],
["A", "K", ("S", "D", "K")]
]
print ("road bike" in fav_stuff)
print ("brownies" in fav_stuff) # Why is this False?
```
%% Output
True
False
%% Cell type:code id: tags:
``` python
# Write a recursive function to search *ANY* list of lists/tuples for a given word
# Modify your code from Warmup 2.C
def search_list_recursive(target, some_list):
''' returns True if thing in some_list, False otherwise'''
for list_item in some_list:
if target == list_item:
return True
elif type(list_item) == list or type(list_item) == tuple:
is_in_next = search_list_recursive(target, list_item)
if is_in_next:
return True
return False # after all possible searching....not found
print(search_list_recursive("apples", fav_stuff))
print(search_list_recursive("D", fav_stuff))
print(search_list_recursive("road bike", fav_stuff))
print(search_list_recursive("pizza", fav_stuff))
```
%% Output
True
True
True
False
%% Cell type:code id: tags:
``` python
# write a function that prints nested lists with indenting
#
def print_with_indenting(directory, indent_level):
for thing in directory:
if type(thing) == list or type(thing) == tuple:
print("\t" * indent_level + str(type(thing)))
print_with_indenting(thing, indent_level + 1)
else:
print("\t" * indent_level + str(thing))
print_with_indenting(fav_stuff, 0)
```
%% Output
road bike
<class 'list'>
PB&J
brownies
spaghetti
apples
<class 'tuple'>
Brooks Ghost 13
hoodie
gloves
macbook air
<class 'list'>
Johndee.com
https://www.weather.gov/mkx/
<class 'list'>
A
K
<class 'tuple'>
S
D
K
%% Cell type:markdown id: tags:
### Dictionaries can have a recursive structure
As can...
- lists
- dictionaries
- JSON objects
%% Cell type:code id: tags:
``` python
ancestry = {
"name": "Evan",
"age": 28,
"born": "Sheboygan",
"parent": {
"name": "Dean",
"age": 53,
"born": "Milwaukee",
"parent": {
"name": "Mike",
"age": 74,
"born": "Racine",
"parent": {
"name": "Bill",
"age": 96,
"born": "La Crosse"
}
}
}
}
```
%% Cell type:code id: tags:
``` python
# let's try to search through a deep dictionary.
def find_place_of_birth(target_name, ancestry_history):
if ancestry_history['name'] == target_name: # base case
return ancestry_history['born']
else:
if 'parent' in ancestry_history:
return find_place_of_birth(target_name, ancestry_history['parent'])
return "Unknown!"
find_place_of_birth("Evan", ancestry)
```
%% Output
'Sheboygan'
%% Cell type:code id: tags:
``` python
# Extra practice...can you predict the outcome?
# run this on your own in Python Tutor
def mystery(a, b):
# precondition: a > 0 and b > 0
if a < 0 or b < 0:
return None
if b == 1:
return a;
return a * mystery( a, b - 1 )
# make a function call here
mystery(7, 5)
```
%% Output
16807
%% Cell type:code id: tags:
``` python
```
%% Cell type:code id: tags:
``` python
# Warmup 0: What is the difference between these two pieces of code?
```
%% Cell type:code id: tags:
``` python
groceries = ["apples", "bananas", "coconuts", "dragonfruit"]
groceries_dicts = []
for grocery in groceries:
grocery_dict = {}
grocery_dict['name'] = grocery
grocery_dict['size'] = len(grocery)
groceries_dicts.append(grocery_dict)
groceries_dicts
```
%% Cell type:code id: tags:
``` python
groceries = ["apples", "bananas", "coconuts", "dragonfruit"]
groceries_dicts = []
grocery_dict = {}
for grocery in groceries:
grocery_dict['name'] = grocery
grocery_dict['size'] = len(grocery)
groceries_dicts.append(grocery_dict)
groceries_dicts
```
%% Cell type:code id: tags:
``` python
# Warmup 1a: Use 'in' to determine if something is in my_list
my_list = ["meet", "me", "after", 84]
```
%% Cell type:code id: tags:
``` python
# Warmup 1b: What about this list?
my_list = [11, "meet", ["me", "them", "us"], [84,19, 22], "school", 2.54]
```
%% Cell type:code id: tags:
``` python
# Warmup 2a: Write a function to find a thing in a list that may have lists in it
my_list = [11, "meet", ["me", "them", "us"], [84,19, 22], "school", 2.54]
def search_list_depth2(target, some_list):
pass
print(search_list_depth2("school", my_list)) # in list
# print(search_list_depth2(22, my_list)) # in nested list
# print(search_list_depth2("house", my_list)) # not anywhere
```
%% Cell type:code id: tags:
``` python
# Warmup 2b: Will our function work on this list? Guess:
list_3_deep = [22, [33, 44, [55, 66], 77 ], 88]
# let's try it with our previous function
print(search_list_depth2(22, list_3_deep)) # in list
print(search_list_depth2(99, list_3_deep)) # not in list
# Write other tests to be sure that it works
```
%% Cell type:code id: tags:
``` python
# Warmup 2c: What about ANY depth list?
# That is the goal of today's lecture
list_3_deep = [22, [33, 44, [55, 66], 77 ], 88]
def search_list_depth_any(target, some_list):
pass
search_list_depth_any(55, list_3_deep)
```
%% Cell type:markdown id: tags:
### Lecture 22: Recursion
After today's Lecture you will be able to:
Define recursion and be able to identify
- the base case
- the recursive case
- infinite recursion
Explain why the following can be recursively defined
- lists
- dictionaries
Trace a recursive function
- involving numeric computation
- involving nested data structures
%% Cell type:markdown id: tags:
## What is Recursion?
Recursion is defined as the process of defining something in terms of itself.
%% Cell type:markdown id: tags:
![image.png](attachment:image.png)
%% Cell type:markdown id: tags:
### Define recursion and be able to identify
- the base case
- the recursive case
- infinite recursion
%% Cell type:code id: tags:
``` python
# In math, you can define the factorial of a number in terms of the number before it.
# Q: What is the value of 84!
# A:
# What are we still missing?
# A:
```
%% Cell type:markdown id: tags:
### A recursive algorithm must have 2 parts:
- the base case....which stops the recursion
- the recursive case...which defines the same process in a smaller way
#### If there is no base case what happens in the above example?
- recursion never ends......infinite recursion
- infinite recursion can also happen if the recursive case does not move towards the base
%% Cell type:markdown id: tags:
### Writing Definitions Recursively
%% Cell type:code id: tags:
``` python
# Define the sequence 1, 3, 5, 7, 9, 11... recursively
# Base Case:
# Recursive Case:
```
%% Cell type:code id: tags:
``` python
# Define whether a positive number is odd recursively
# Base Case:
# Recursive Case:
```
%% Cell type:markdown id: tags:
### Writing Recursive Code
%% Cell type:code id: tags:
``` python
def factorial(n):
pass
print(factorial(0))
# print(factorial(3))
# print(factorial(6))
```
%% Cell type:markdown id: tags:
### Write and try `is_odd` in PythonTutor
%% Cell type:code id: tags:
``` python
def is_odd(n):
pass
is_odd(7)
```
%% Cell type:markdown id: tags:
### Can we write them iteratively instead?
%% Cell type:code id: tags:
``` python
def factorial_itr(n):
pass
print(factorial_itr(0))
# print(factorial_itr(3))
# print(factorial_itr(6))
```
%% Cell type:markdown id: tags:
### Other Recursive Problems
%% Cell type:code id: tags:
``` python
# Go back and complete Warmup 2.C
```
%% Cell type:code id: tags:
``` python
# The Collatz Conjecture problem
# Conjecture: Any positive integer n, put through the below equation
# will always converge to 1.
#
# https://en.wikipedia.org/wiki/Collatz_conjecture
# https://www.youtube.com/watch?v=5mFpVDpKX70
# US$500 for solving. And likely an honorary doctorate.
# Run this in Python Tutor on your own
def collatz(n):
print(n)
if n == 1:
return 1 # base case
elif n % 2 == 0:
return collatz(n//2)
else:
return collatz (3*n+1)
collatz(13) # try other numbers
```
%% Cell type:markdown id: tags:
### Trace a recursive function involving nested data structures
%% Cell type:code id: tags:
``` python
fav_stuff = [ "road bike",
["PB&J", "brownies", "spaghetti", "apples"] ,
("Brooks Ghost 13", "hoodie", "gloves"),
"macbook air",
[ "Johndee.com", "https://www.weather.gov/mkx/"],
["A", "K", ("S", "D", "K")]
]
print ("road bike" in fav_stuff)
print ("brownies" in fav_stuff) # Why is this False?
```
%% Cell type:code id: tags:
``` python
# Write a recursive function to search *ANY* list of lists/tuples for a given word
# Modify your code from Warmup 2.C
def search_list_recursive(target, some_list):
pass
print(search_list_recursive("apples", fav_stuff))
# print(search_list_recursive("D", fav_stuff))
# print(search_list_recursive("road bike", fav_stuff))
# print(search_list_recursive("pizza", fav_stuff))
```
%% Cell type:code id: tags:
``` python
# Write a function that prints nested lists with indenting
#
def print_with_indenting(directory, indent_level):
for thing in directory:
if type(thing) == list or type(thing) == tuple:
print("\t" * indent_level + str(type(thing)))
print_with_indenting(thing, indent_level + 1)
else:
print("\t" * indent_level + str(thing))
print_with_indenting(fav_stuff, 0)
```
%% Cell type:markdown id: tags:
### Dictionaries can have a recursive structure
As can...
- lists
- dictionaries
- JSON objects
%% Cell type:code id: tags:
``` python
ancestry = {
"name": "Evan",
"age": 28,
"born": "Sheboygan",
"parent": {
"name": "Dean",
"age": 53,
"born": "Milwaukee",
"parent": {
"name": "Mike",
"age": 74,
"born": "Racine",
"parent": {
"name": "Bill",
"age": 96,
"born": "La Crosse"
}
}
}
}
```
%% Cell type:code id: tags:
``` python
# let's try to search through a deep dictionary.
def find_place_of_birth(target_name, ancestry_history):
if ancestry_history['name'] == target_name: # base case
return ancestry_history['born']
else:
if 'parent' in ancestry_history:
return ???
return "Unknown!"
find_place_of_birth("Evan", ancestry)
```
%% Cell type:code id: tags:
``` python
# Extra practice...can you predict the outcome?
# run this on your own in Python Tutor
def mystery(a, b):
# precondition: a > 0 and b > 0
if a < 0 or b < 0:
return None
if b == 1:
return a;
return a * mystery( a, b - 1 )
# make a function call here
mystery(7, 5)
```
%% Cell type:code id: tags:
``` python
# Warmup 1: Complete the recursive function.
# Write a function that prints nested lists with indenting
#
fav_stuff = [ "road bike",
["PB&J", "brownies", "spaghetti", "apples"] ,
("Brooks Ghost 13", "hoodie", "gloves"),
"macbook air",
[ "Johndee.com", "https://www.weather.gov/mkx/"],
["A", "K", ("S", "D", "K")]
]
def print_with_indenting(directory, indent_level):
for subitem in directory:
if type(subitem) == list or type(subitem) == tuple:
print("\t" * indent_level + str(type(subitem)))
# TODO make recursive call
print_with_indenting(subitem, indent_level + 1)
else:
print("\t" * indent_level + str(subitem))
print_with_indenting(fav_stuff, 0)
```
%% Output
road bike
<class 'list'>
PB&J
brownies
spaghetti
apples
<class 'tuple'>
Brooks Ghost 13
hoodie
gloves
macbook air
<class 'list'>
Johndee.com
https://www.weather.gov/mkx/
<class 'list'>
A
K
<class 'tuple'>
S
D
K
%% Cell type:markdown id: tags:
[PythonTutor Link](https://pythontutor.com/visualize.html#code=def%20mystery%28a,%20b%29%3A%20%0A%23%20precondition%3A%20assume%20a%20%3E%200%20and%20b%20%3E%200%0A%20%20%20%20if%20b%20%3D%3D%201%3A%20%0A%20%20%20%20%20%20%20%20return%20a%3B%0A%20%20%20%20return%20a%20*%20mystery%28%20a,%20b%20-%201%20%29%0A%0A%23%20make%20a%20function%20call%20here%0Amystery%287,%205%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)
%% Cell type:code id: tags:
``` python
# Warmup 2: Trace Recursion by hand .... possible exam question
def mystery(a, b):
# precondition: assume a > 0 and b > 0
if b == 1:
return a;
return a * mystery( a, b - 1 )
# make a function call here
mystery(7, 5)
#Q: What would be the result if we call
#. mystery(-3, -1) ??
# If b starts at -1, and we subtract 1 each time we call a mystery, it will never == 1
```
%% Output
16807
%% Cell type:markdown id: tags:
## Lecture 23: Functions are Objects!
As we have learned previously, all variables in Python are stored as objects.
This is also true for functions, and it gives us more power as programmers.
**Learning Objectives:**
- Define a function reference and trace code that uses function references.
- Explain the default use of sorted() on lists of tuples, and dictionaries.
- Sort a list of tuples, a list of dictionaries, or a dictionary using a function as a key.
- Use a lambda expression when sorting.
%% Cell type:code id: tags:
``` python
# function references
# try this in Python Tutor
x = [1,2,3]
y = x
def f(some_list): # what is f? its a function but also an object
return some_list[-1]
z = f(y) # z stores the result of a call to f
g = f # what is g? it is a reference to an object that is a function
# TODO: similar to line 10, store the result of a call to g
w = g(x) # calls the same function
w
```
%% Output
3
%% Cell type:markdown id: tags:
### Define a function reference and trace code that uses function references.
%% Cell type:markdown id: tags:
![function%20reference.png](attachment:function%20reference.png)
%% Cell type:markdown id: tags:
[PythonTutor Link](https://pythontutor.com/visualize.html#code=def%20hammer%28%29%3A%0A%20%20%20%20print%28%22tap%20tap%20tap%22%29%0A%20%20%20%20%0Adef%20call_n_times%28f,%20n%29%3A%0A%20%20%20%20for%20i%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20f%28%29%0A%0Acall_n_times%28hammer,%203%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)
%% Cell type:code id: tags:
``` python
# function references can be passed as arguments ...Wow!
# first: try this in Python Tutor
def hammer():
print("tap tap tap")
# then on your own: define a function called screwdriver
def screwdriver():
print("churn churn churn")
def call_n_times(f, n):
for i in range(n):
f()
call_n_times(hammer, 3)
# then on your own: invoke call_n_times with screwdriver and 5 as arguments
call_n_times(screwdriver, 5)
```
%% Output
tap tap tap
tap tap tap
tap tap tap
churn churn churn
churn churn churn
churn churn churn
churn churn churn
churn churn churn
%% Cell type:markdown id: tags:
## Your turn!
Calculate the distance between two points using either the manhattan or euclidean distance.
%% Cell type:markdown id: tags:
![image.png](attachment:image.png)
Source: https://www.researchgate.net/figure/Example-of-Euclidean-and-Manhattan-distances-between-two-points-A-and-B-The-Euclidean_fig8_333430988
%% Cell type:markdown id: tags:
### Review: NamedTuples
We create a namedtuple `Point` with named attributes `x` and `y`. We then create lists of points we want to calculate distances between
%% Cell type:code id: tags:
``` python
from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
left_points = [
Point(0, 0),
Point(3, 3),
Point(2, 2)
]
right_points = [
Point(5, 5),
Point(0, 3),
Point(2, 2)
]
```
%% Cell type:markdown id: tags:
### Complete the function `calculate_distances`
%% Cell type:markdown id: tags:
We already did the math behind `manhattan_distance` and `euclidean_distance` for you!
**Hint:** `distance_algo` should be a reference to a function that calculates distance between two points.
Then, call calculate_distances measuring first in manhattan_distance, then euclidean_distance.
%% Cell type:code id: tags:
``` python
import math
def manhattan_distance(point1, point2):
dist_x = abs(point1.x - point2.x)
dist_y = abs(point1.y - point2.y)
return dist_x + dist_y
def euclidean_distance(point1, point2):
dist_x = (point1.x - point2.x) ** 2
dist_y = (point1.y - point2.y) ** 2
return math.sqrt(dist_x + dist_y)
def calculate_distances(distance_algo):
for i in range(len(left_points)):
left_point = left_points[i]
right_point = right_points[i]
print(distance_algo(left_point, right_point))
calculate_distances(manhattan_distance)
calculate_distances(euclidean_distance)
```
%% Output
10
3
0
7.0710678118654755
3.0
0.0
%% Cell type:markdown id: tags:
### Explain the default use of sorted() on lists of tuples, and on dictionaries.
%% Cell type:code id: tags:
``` python
# first... did you know that sort/sorted takes a 2nd argument called reverse?
populations = [55, 77, 33, 99, 22]
# TODO: sort populations in reverse
sorted(populations, reverse=True)
```
%% Output
[99, 77, 55, 33, 22]
%% Cell type:code id: tags:
``` python
# Sorting part 1....how are lists of tuples sorted?
# olympic womens hockey badgers...first, last, age
owhockey_badgers = [ ("Hillary", "Knight", 32 ),
("Brianna", "Decker", 30),
("Amanda", "Kessel", 30),
("Alex", "Cavalenni", 30),
("Caroline", "Harvey", 19),
("Abbey", "Roque", 24)
]
# call sorted on this list of tuples
sorted(owhockey_badgers)
# what did this make? How was it sorted?
```
%% Output
[('Abbey', 'Roque', 24),
('Alex', 'Cavalenni', 30),
('Amanda', 'Kessel', 30),
('Brianna', 'Decker', 30),
('Caroline', 'Harvey', 19),
('Hillary', 'Knight', 32)]
%% Cell type:code id: tags:
``` python
# sorting part 2: define a function that returns a value from a tuple
def select0(some_tuple): # function must have exactly one parameter
return some_tuple[0]
def select1(some_tuple):
return some_tuple[1]
def select2(some_tuple):
return some_tuple[2]
# Test these functions on the tuple ("Mike", "Gurmail", "Cole")
my_tuple = ("Mike", "Gurmail", "Cole")
select1(my_tuple)
```
%% Output
'Gurmail'
%% Cell type:code id: tags:
``` python
# call sorted using the 'key' argument
# sort and sorted can take a parameter named key
# key is a reference to a function!
sorted(owhockey_badgers, key=select2)
```
%% Output
[('Caroline', 'Harvey', 19),
('Abbey', 'Roque', 24),
('Brianna', 'Decker', 30),
('Amanda', 'Kessel', 30),
('Alex', 'Cavalenni', 30),
('Hillary', 'Knight', 32)]
%% Cell type:code id: tags:
``` python
# sort the list of tuples based on the last name
sorted(owhockey_badgers, key=select1)
```
%% Output
[('Alex', 'Cavalenni', 30),
('Brianna', 'Decker', 30),
('Caroline', 'Harvey', 19),
('Amanda', 'Kessel', 30),
('Hillary', 'Knight', 32),
('Abbey', 'Roque', 24)]
%% Cell type:code id: tags:
``` python
# sort the list of tuples based on the age
sorted(owhockey_badgers, key=select2)
```
%% Output
[('Caroline', 'Harvey', 19),
('Abbey', 'Roque', 24),
('Brianna', 'Decker', 30),
('Amanda', 'Kessel', 30),
('Alex', 'Cavalenni', 30),
('Hillary', 'Knight', 32)]
%% Cell type:markdown id: tags:
### Using `lambda`
- `lambda` functions are a way to abstract a function reference
- lambdas are simple functions with:
- multiple possible parameters
- single expression line as the function body
- lambdas are useful abstractions for:
- mathematical functions
- lookup operations
- lambdas are often associated with a collection of values within a list
- Syntax:
```python
lambda parameters: expression
```
%% Cell type:code id: tags:
``` python
# sorting part 3....using lambdas
'''
def no_name(each_tuple):
return each_tuple[-1]
'''
sorted(owhockey_badgers, key = lambda each_tuple : each_tuple[-1])
# read the lambda as: my no-name function has each_tuple as a parameter
# and returns each_tuple[-1] (the last element)
# the variable 'each_tuple' is like a function parameter
```
%% Output
[('Caroline', 'Harvey', 19),
('Abbey', 'Roque', 24),
('Brianna', 'Decker', 30),
('Amanda', 'Kessel', 30),
('Alex', 'Cavalenni', 30),
('Hillary', 'Knight', 32)]
%% Cell type:code id: tags:
``` python
# TODO: sort the list by the length of the first name
'''
def no_name(x):
return len(x[0])
'''
sorted(owhockey_badgers, key = lambda x : len(x[0]))
```
%% Output
[('Alex', 'Cavalenni', 30),
('Abbey', 'Roque', 24),
('Amanda', 'Kessel', 30),
('Hillary', 'Knight', 32),
('Brianna', 'Decker', 30),
('Caroline', 'Harvey', 19)]
%% Cell type:code id: tags:
``` python
# TODO: Sort the list by the length of their full name
'''
def no_name(player):
return len(player[0]) + len(player[1])
'''
sorted(owhockey_badgers, key = lambda player : len(player[0]) + len(player[1]))
```
%% Output
[('Abbey', 'Roque', 24),
('Amanda', 'Kessel', 30),
('Hillary', 'Knight', 32),
('Brianna', 'Decker', 30),
('Alex', 'Cavalenni', 30),
('Caroline', 'Harvey', 19)]
%% Cell type:markdown id: tags:
### OK, I can sort a list of tuples....what about a list of dictionaries?
%% Cell type:code id: tags:
``` python
hurricanes = [
{"name": "Calvin", "year": 2000},
{"name": "Alexandria", "year": 1980, "speed": 100},
{"name": "Blanc", "year": 1990, "speed": 250},
]
# call sorted on hurricanes and use a lambda expression to grab the year
sorted(hurricanes, key = lambda d : d["year"], reverse=True)
```
%% Output
[{'name': 'Calvin', 'year': 2000},
{'name': 'Blanc', 'year': 1990, 'speed': 250},
{'name': 'Alexandria', 'year': 1980, 'speed': 100}]
%% Cell type:code id: tags:
``` python
# sort hurricanes alphabetically by name
# for you to do on your own...see the above example
sorted(hurricanes, key = lambda d : d["name"])
```
%% Output
[{'name': 'Alexandria', 'year': 1980, 'speed': 100},
{'name': 'Blanc', 'year': 1990, 'speed': 250},
{'name': 'Calvin', 'year': 2000}]
%% Cell type:code id: tags:
``` python
# on your own, sort hurricanes by speed.....
sorted(hurricanes, key = lambda d : d.get("speed", 0))
```
%% Output
[{'name': 'Calvin', 'year': 2000},
{'name': 'Alexandria', 'year': 1980, 'speed': 100},
{'name': 'Blanc', 'year': 1990, 'speed': 250}]
%% Cell type:markdown id: tags:
### This is all great, but what I'd really like to do is to sort dictionaries!
%% Cell type:code id: tags:
``` python
menu = { 'pie': 3.95,
'ala mode':1.50,
'donut': 1.25,
'cookie': 0.79,
'milk':1.65,
'loaf': 5.99,
'hot dog': 4.99}
# sorted (dict) returns a list of the keys sorted
sorted(menu)
```
%% Output
['ala mode', 'cookie', 'donut', 'hot dog', 'loaf', 'milk', 'pie']
%% Cell type:code id: tags:
``` python
# but we can make progress on this by using the .items() method
menu.items()
```
%% Output
dict_items([('pie', 3.95), ('ala mode', 1.5), ('donut', 1.25), ('cookie', 0.79), ('milk', 1.65), ('loaf', 5.99), ('hot dog', 4.99)])
%% Cell type:code id: tags:
``` python
# that looks like a list of tuples!
# let's sort menu.items() the same way we sorted a list of tuples
sorted(menu.items(), key = lambda t : t[0] ) # set the sorting key to a lambda expressoin
```
%% Output
[('ala mode', 1.5),
('cookie', 0.79),
('donut', 1.25),
('hot dog', 4.99),
('loaf', 5.99),
('milk', 1.65),
('pie', 3.95)]
%% Cell type:code id: tags:
``` python
# now let's turn this list of tuples into a dict
dict(sorted(menu.items(), key=lambda thing: thing[0]))
```
%% Output
{'ala mode': 1.5,
'cookie': 0.79,
'donut': 1.25,
'hot dog': 4.99,
'loaf': 5.99,
'milk': 1.65,
'pie': 3.95}
%% Cell type:code id: tags:
``` python
# can you change the previous code to sort by price?
dict(sorted(menu.items(), key=lambda thing: thing[1]))
```
%% Output
{'cookie': 0.79,
'donut': 1.25,
'ala mode': 1.5,
'milk': 1.65,
'pie': 3.95,
'hot dog': 4.99,
'loaf': 5.99}
%% Cell type:code id: tags:
``` python
# can you sort the dictionary by the length of the name?
dict(sorted(menu.items(), key=lambda thing: len(thing[0])))
```
%% Output
{'pie': 3.95,
'milk': 1.65,
'loaf': 5.99,
'donut': 1.25,
'cookie': 0.79,
'hot dog': 4.99,
'ala mode': 1.5}
%% Cell type:markdown id: tags:
## After Lecture
%% Cell type:code id: tags:
``` python
# Practice sorting a list of tuples
# Practice sorting a list of dictionaries
# Practice sorting a dictionary by keys
# Practice sorting a dictionary by values
```
%% Cell type:code id: tags:
``` python
# Warmup 1: Complete the recursive function.
# Write a function that prints nested lists with indenting
#
fav_stuff = [ "road bike",
["PB&J", "brownies", "spaghetti", "apples"] ,
("Brooks Ghost 13", "hoodie", "gloves"),
"macbook air",
[ "Johndee.com", "https://www.weather.gov/mkx/"],
["A", "K", ("S", "D", "K")]
]
def print_with_indenting(directory, indent_level):
for subitem in directory:
if type(subitem) == list or type(subitem) == tuple:
print("\t" * indent_level + str(type(subitem)))
# TODO make recursive call
else:
print("\t" * indent_level + str(subitem))
print_with_indenting(fav_stuff, 0)
```
%% Cell type:markdown id: tags:
[PythonTutor Link](https://pythontutor.com/visualize.html#code=def%20mystery%28a,%20b%29%3A%20%0A%23%20precondition%3A%20assume%20a%20%3E%200%20and%20b%20%3E%200%0A%20%20%20%20if%20b%20%3D%3D%201%3A%20%0A%20%20%20%20%20%20%20%20return%20a%3B%0A%20%20%20%20return%20a%20*%20mystery%28%20a,%20b%20-%201%20%29%0A%0A%23%20make%20a%20function%20call%20here%0Amystery%287,%205%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)
%% Cell type:code id: tags:
``` python
# Warmup 2: Trace Recursion by hand .... possible exam question
def mystery(a, b):
# precondition: assume a > 0 and b > 0
if b == 1:
return a;
return a * mystery( a, b - 1 )
# make a function call here
mystery(7, 5)
#Q: What would be the result if we call
#. mystery(-3, -1) ??
```
%% Output
16807
%% Cell type:markdown id: tags:
## Lecture 23: Functions are Objects!
As we have learned previously, all variables in Python are stored as objects.
This is also true for functions, and it gives us more power as programmers.
**Learning Objectives:**
- Define a function reference and trace code that uses function references.
- Explain the default use of sorted() on lists of tuples, and dictionaries.
- Sort a list of tuples, a list of dictionaries, or a dictionary using a function as a key.
- Use a lambda expression when sorting.
%% Cell type:code id: tags:
``` python
# function references
# try this in Python Tutor
x = [1,2,3]
y = x
def f(some_list): # what is f?
return some_list[-1]
z = f(y) # z stores the result of a call to f
g = f # what is g?
# TODO: similar to line 10, store the result of a call to g
```
%% Cell type:markdown id: tags:
### Define a function reference and trace code that uses function references.
%% Cell type:markdown id: tags:
![function%20reference.png](attachment:function%20reference.png)
%% Cell type:markdown id: tags:
[PythonTutor Link](https://pythontutor.com/visualize.html#code=def%20hammer%28%29%3A%0A%20%20%20%20print%28%22tap%20tap%20tap%22%29%0A%20%20%20%20%0Adef%20call_n_times%28f,%20n%29%3A%0A%20%20%20%20for%20i%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20f%28%29%0A%0Acall_n_times%28hammer,%203%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)
%% Cell type:code id: tags:
``` python
# function references can be passed as arguments ...Wow!
# first: try this in Python Tutor
def hammer():
print("tap tap tap")
# then on your own: define a function called screwdriver
def screwdriver():
pass
def call_n_times(f, n):
for i in range(n):
f()
call_n_times(hammer, 3)
# then on your own: invoke call_n_times with screwdriver and 5 as arguments
```
%% Output
tap tap tap
tap tap tap
tap tap tap
%% Cell type:markdown id: tags:
## Your turn!
Calculate the distance between two points using either the manhattan or euclidean distance.
%% Cell type:markdown id: tags:
![image.png](attachment:image.png)
Source: https://www.researchgate.net/figure/Example-of-Euclidean-and-Manhattan-distances-between-two-points-A-and-B-The-Euclidean_fig8_333430988
%% Cell type:markdown id: tags:
### Review: NamedTuples
We create a namedtuple `Point` with named attributes `x` and `y`. We then create lists of points we want to calculate distances between
%% Cell type:code id: tags:
``` python
from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
left_points = [
Point(0, 0),
Point(3, 3),
Point(2, 2),
# TODO: Add another point!
]
right_points = [
Point(5, 5),
Point(0, 3),
Point(2, 2),
# TODO: Add another point!
]
```
%% Cell type:markdown id: tags:
### Complete the function `calculate_distances`
%% Cell type:markdown id: tags:
We already did the math behind `manhattan_distance` and `euclidean_distance` for you!
**Hint:** `distance_algo` should be a reference to a function that calculates distance between two points.
Then, call calculate_distances measuring first in manhattan_distance, then euclidean_distance.
%% Cell type:code id: tags:
``` python
import math
def manhattan_distance(point1, point2):
dist_x = abs(point1.x - point2.x)
dist_y = abs(point1.y - point2.y)
return dist_x + dist_y
def euclidean_distance(point1, point2):
dist_x = (point1.x - point2.x) ** 2
dist_y = (point1.y - point2.y) ** 2
return math.sqrt(dist_x + dist_y)
# TODO: Complete this function!
def calculate_distances(distance_algo):
pass
# TODO: Calculate the distance between the points using manhattan distance
# TODO: Calculate the distance between the points using euclidean distance
```
%% Cell type:markdown id: tags:
### Explain the default use of sorted() on lists of tuples, and on dictionaries.
%% Cell type:code id: tags:
``` python
# first... did you know that sort/sorted takes a 2nd argument called reverse?
populations = [55, 77, 33, 99, 22]
# TODO: sort populations in reverse
```
%% Cell type:code id: tags:
``` python
# Sorting part 1....how are lists of tuples sorted?
# olympic womens hockey badgers...first, last, age
owhockey_badgers = [ ("Hillary", "Knight", 32 ),
("Brianna", "Decker", 30),
("Amanda", "Kessel", 30),
("Alex", "Cavalenni", 30),
("Caroline", "Harvey", 19),
("Abbey", "Roque", 24)
]
# call sorted on this list of tuples
sorted(owhockey_badgers)
# what did this make? How was it sorted?
```
%% Output
[('Abbey', 'Roque', 24),
('Alex', 'Cavalenni', 30),
('Amanda', 'Kessel', 30),
('Brianna', 'Decker', 30),
('Caroline', 'Harvey', 19),
('Hillary', 'Knight', 32)]
%% Cell type:code id: tags:
``` python
# sorting part 2: define a function that returns a value from a tuple
def select0(some_tuple): # function must have exactly one parameter
return some_tuple[0]
def select1(some_tuple):
return some_tuple[1]
def select2(some_tuple):
return some_tuple[2]
# Test these functions on the tuple ("Mike", "Gurmail", "Cole")
```
%% Cell type:code id: tags:
``` python
# call sorted using the 'key' argument
# sort and sorted can take a parameter named key
# key is a reference to a function!
sorted(owhockey_badgers, key=select2)
```
%% Cell type:code id: tags:
``` python
# sort the list of tuples based on the last name
```
%% Cell type:code id: tags:
``` python
# sort the list of tuples based on the age
```
%% Cell type:markdown id: tags:
### Using `lambda`
- `lambda` functions are a way to abstract a function reference
- lambdas are simple functions with:
- multiple possible parameters
- single expression line as the function body
- lambdas are useful abstractions for:
- mathematical functions
- lookup operations
- lambdas are often associated with a collection of values within a list
- Syntax:
```python
lambda parameters: expression
```
%% Cell type:code id: tags:
``` python
# sorting part 3....using lambdas
'''
def no_name(each_tuple):
return each_tuple[-1]
'''
sorted(owhockey_badgers, key = lambda each_tuple : each_tuple[-1])
# read the lambda as: my no-name function has each_tuple as a parameter
# and returns each_tuple[-1] (the last element)
# the variable 'each_tuple' is like a function parameter
```
%% Cell type:code id: tags:
``` python
# TODO: sort the list by the length of the first name
'''
def no_name(x):
return len(x[0])
'''
```
%% Cell type:code id: tags:
``` python
# TODO: Sort the list by the length of their full name
```
%% Cell type:markdown id: tags:
### OK, I can sort a list of tuples....what about a list of dictionaries?
%% Cell type:code id: tags:
``` python
hurricanes = [
{"name": "Calvin", "year": 2000},
{"name": "Alexandria", "year": 1980, "speed": 100},
{"name": "Blanc", "year": 1990, "speed": 250},
]
# call sorted on hurricanes and use a lambda expression to grab the year
sorted(hurricanes, key = lambda d : d["year"], reverse=True)
```
%% Output
[{'name': 'Calvin', 'year': 2000},
{'name': 'Blanc', 'year': 1990, 'speed': 250},
{'name': 'Alexandria', 'year': 1980, 'speed': 100}]
%% Cell type:code id: tags:
``` python
# sort hurricanes alphabetically by name
# for you to do on your own...see the above example
```
%% Cell type:code id: tags:
``` python
# on your own, sort hurricanes by speed.....
```
%% Cell type:markdown id: tags:
### This is all great, but what I'd really like to do is to sort dictionaries!
%% Cell type:code id: tags:
``` python
menu = { 'pie': 3.95,
'ala mode':1.50,
'donut': 1.25,
'cookie': 0.79,
'milk':1.65,
'loaf': 5.99,
'hot dog': 4.99}
# sorted (dict) returns a list of the keys sorted
sorted(menu)
```
%% Cell type:code id: tags:
``` python
# but we can make progress on this by using the .items() method
menu.items()
```
%% Cell type:code id: tags:
``` python
# that looks like a list of tuples!
# let's sort menu.items() the same way we sorted a list of tuples
sorted(menu.items(), key = lambda t : t[0] ) # set the sorting key to a lambda expressoin
```
%% Cell type:code id: tags:
``` python
# now let's turn this list of tuples into a dict
```
%% Cell type:code id: tags:
``` python
# can you change the previous code to sort by price?
```
%% Cell type:code id: tags:
``` python
# can you sort the dictionary by the length of the name?
```
%% Cell type:markdown id: tags:
## After Lecture
%% Cell type:code id: tags:
``` python
# Practice sorting a list of tuples
# Practice sorting a list of dictionaries
# Practice sorting a dictionary by keys
# Practice sorting a dictionary by values
```
%% Cell type:code id: tags:
``` python
# Warmup 1a: Sort this list by the length of each word using a normal function
fruits = ["blackberry", "apple", "banana", "fig", "blueberry", "strawberry"]
def get_fruit_len(f):
return len(f)
# Why might we use sorted rather than sort?
sorted(fruits, key=get_fruit_len)
```
%% Output
['fig', 'apple', 'banana', 'blueberry', 'blackberry', 'strawberry']
%% Cell type:code id: tags:
``` python
# Warmup 1b: Sort this list by the length of each word using a lambda
fruits = ["blackberry", "apple", "banana", "fig", "blueberry", "strawberry"]
sorted(fruits, key=lambda f:len(f))
```
%% Output
['fig', 'apple', 'banana', 'blueberry', 'blackberry', 'strawberry']
%% Cell type:code id: tags:
``` python
# Warmup 2: Define: What is a lambda function?
# A lambda is an abstraction (think: shortcut) to creating a function
# We remove the def, name, and return statement of the function definition.
# We just describe the parameter and the return value
```
%% Cell type:code id: tags:
``` python
# Warmup 3: Sort this dictionary by their total enrollment
enrollments = { "Wisconsin": 45540,
"Michigan": 47907,
"Illinois": 52331,
"Iowa": 30448,
"Minnesota": 52017,
"Ohio State": 61369,
"Northwestern": 22316}
enrollment_tuples = enrollments.items()
sorted_enrollment_tuples = sorted(enrollment_tuples, key=lambda t: t[1])
dict(sorted_enrollment_tuples)
```
%% Output
{'Northwestern': 22316,
'Iowa': 30448,
'Wisconsin': 45540,
'Michigan': 47907,
'Minnesota': 52017,
'Illinois': 52331,
'Ohio State': 61369}
%% Cell type:code id: tags:
``` python
# Warmup 4: Sort this list of dictionaries by 'name'
volunteers = [ {"name": "Sky", "hours": 53},
{"name":"Patrice", "hours": 72},
{"name":"Gabriella", "hours": 45},
{"name": "Jade", "hours": 62} ]
sorted(volunteers, key = lambda d:d['name'])
```
%% Output
[{'name': 'Gabriella', 'hours': 45},
{'name': 'Jade', 'hours': 62},
{'name': 'Patrice', 'hours': 72},
{'name': 'Sky', 'hours': 53}]
%% Cell type:code id: tags:
``` python
# Warmup 5: Sort this dictionary of lists by the length of the list
cities_by_county = {"Dane": ["Madison", "Sun Prairie", "Middleton", "Waunakee"],
"Milwaukee": ["Milwaukee", "West Allis", "Wauwatosa"],
"Rock": ["Janesville", "Beloit"],
"Waukesha": ["Brookfield"]}
cities_by_county_tuples = cities_by_county.items()
sorted_cities_by_county_tuples = sorted(cities_by_county_tuples, key = lambda t: len(t[1]))
dict(sorted_cities_by_county_tuples)
```
%% Output
{'Waukesha': ['Brookfield'],
'Rock': ['Janesville', 'Beloit'],
'Milwaukee': ['Milwaukee', 'West Allis', 'Wauwatosa'],
'Dane': ['Madison', 'Sun Prairie', 'Middleton', 'Waunakee']}
%% Cell type:code id: tags:
``` python
# Warmup 6: Create a list of all fruits that contain 'berry'
fruits = ["blackberry", "apple", "banana", "fig", "blueberry", "strawberry"]
berry_good_fruits = []
for fruit in fruits:
if 'berry' in fruit:
berry_good_fruits.append(fruit)
berry_good_fruits
```
%% Output
['blackberry', 'blueberry', 'strawberry']
%% Cell type:markdown id: tags:
# Lecture 24: Iterators and Comprehensions
Learning Objectives:
- Create list and dictionary comprehensions
- Use the correct vocabulary to describe iteration
- iterable, sequence, iterator
- Determine if an object is an iterable, or if it is an iterator
- try to use iter() to determine if an object is an iterable
- try to use next() to determine if an object is an iterator
- Use iterator/iterable language to open and process files
%% Cell type:markdown id: tags:
## List Comprehensions
%% Cell type:code id: tags:
``` python
# Do we have a shorter way to complete Warmup 6?
# https://en.wikipedia.org/wiki/Code_golf
# Yes! Using List Comprehensions
fruits = ["blackberry", "apple", "banana", "fig", "blueberry", "strawberry"]
[f for f in fruits if 'berry' in f]
```
%% Output
['blackberry', 'blueberry', 'strawberry']
%% Cell type:code id: tags:
``` python
# What other ways could we filter our fruits list?
fruits = ["blackberry", "apple", "banana", "fig", "blueberry", "strawberry"]
# All fruits that contain berry (we just did this!)
# All fruits that start with the letter 'b'
# All fruits with short names
# The length of every fruit name
# ...
```
%% Cell type:code id: tags:
``` python
# All fruits that start with the letter 'b'
[f for f in fruits if f.startswith('b')]
```
%% Output
['blackberry', 'banana', 'blueberry']
%% Cell type:code id: tags:
``` python
# All fruits with short names
[f for f in fruits if len(f) < 6]
```
%% Output
['apple', 'fig']
%% Cell type:code id: tags:
``` python
# The length of every fruit name
[len(f) for f in fruits]
```
%% Output
[10, 5, 6, 3, 9, 10]
%% Cell type:markdown id: tags:
### More List Comprehensions
%% Cell type:code id: tags:
``` python
# Convert these Fahrenheit temps to an int in Celsius using C = 5/9 * (F-32)
temps = [32, 45, 90, 212]
# First, write using a traditional for loop...
cel_temps = []
for f in temps:
temp_cel = (5/9) * (f-32)
cel_temps.append(temp_cel)
cel_temps
```
%% Output
[0.0, 7.222222222222222, 32.22222222222222, 100.0]
%% Cell type:code id: tags:
``` python
# Then, try writing it as a list comprehension!
[5/9 * (f-32) for f in temps]
```
%% Output
[0.0, 7.222222222222222, 32.22222222222222, 100.0]
%% Cell type:code id: tags:
``` python
# What if temps were strings?
temps = ["32", "", "45", "90", "212"]
[5/9 * (int(f)-32) for f in temps if f != ""]
```
%% Output
[0.0, 7.222222222222222, 32.22222222222222, 100.0]
%% Cell type:markdown id: tags:
### Even More List Comprehensions
%% Cell type:code id: tags:
``` python
# What ways could we filter this list of volunteers?
volunteers = [ {"name": "Sky", "hours": 53},
{"name": "Patrice", "hours": 72},
{"name": "Gabriella", "hours": 45},
{"name": "Jade", "hours": 62}
]
# Those that have volunteered atleast 60 hours
# Those with short names
# ...
```
%% Cell type:code id: tags:
``` python
# Those that have volunteered atleast 60 hours
[d['name'] for d in volunteers if d['hours'] > 60]
```
%% Output
['Patrice', 'Jade']
%% Cell type:code id: tags:
``` python
# Those with short names
[d['name'] for d in volunteers if len(d['name']) < 5]
```
%% Output
['Sky', 'Jade']
%% Cell type:code id: tags:
``` python
# What if we wanted to keep the name and hours?
[d for d in volunteers if len(d['name']) < 5]
```
%% Output
[{'name': 'Sky', 'hours': 53}, {'name': 'Jade', 'hours': 62}]
%% Cell type:markdown id: tags:
### Dictionary Comprehensions
Same thing as a list comprehension, but with a key *and* value!
%% Cell type:code id: tags:
``` python
# Generate a dictionary of numbers and their squares! e.g. {1: 1, 2: 4, 3: 9, 4: 16, ...}
nums = [1, 2, 3, 4, 5, 6, 7]
square_mapping_dict = {num: num ** 2 for num in nums}
square_mapping_dict
```
%% Output
{1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49}
%% Cell type:code id: tags:
``` python
# What ways could we filter this dictionary of people's scores?
scores_dict = {"Bob": [18, 72, 83],
"Cindy" : [27, 11, 55, 73, 87],
"Alice": [16, 33, 42, 89, 90],
"Meena": [39, 93, 9, 3, 55, 72, 19]}
# A dictionary of how many scores each player has
# A dictionary of everyone's highest score
# A dictionary of everyone's average score
# ...
```
%% Cell type:code id: tags:
``` python
# Tip: We can use "tuple unpacking" in our for loop!
# An old fashioned for loop...
new_scores_dict = {}
for (player, scores) in scores_dict.items():
new_scores_dict[player] = len(scores)
new_scores_dict
```
%% Output
{'Bob': 3, 'Cindy': 5, 'Alice': 5, 'Meena': 7}
%% Cell type:code id: tags:
``` python
# A dictionary of how many scores each player has.
{player : len(scores) for (player, scores) in scores_dict.items()}
```
%% Output
{'Bob': 3, 'Cindy': 5, 'Alice': 5, 'Meena': 7}
%% Cell type:code id: tags:
``` python
# A dictionary of everyone's highest score
{player : max(scores) for (player, scores) in scores_dict.items()}
```
%% Output
{'Bob': 83, 'Cindy': 87, 'Alice': 90, 'Meena': 93}
%% Cell type:code id: tags:
``` python
# A dictionary of everyone's average score
{player : sum(scores) / len(scores) for (player, scores) in scores_dict.items()}
```
%% Output
{'Bob': 57.666666666666664,
'Cindy': 50.6,
'Alice': 54.0,
'Meena': 41.42857142857143}
%% Cell type:code id: tags:
``` python
# Challenge: A sorted dictionary of everyone's average score.
avg_scores = {player : sum(scores) / len(scores) for (player, scores) in scores_dict.items()}
# Convert the dictionary to a list of tuples, sort based on the score, and turn back into a dict.
dict(sorted(avg_scores.items(), key=lambda t: t[1]))
```
%% Output
{'Meena': 41.42857142857143,
'Cindy': 50.6,
'Alice': 54.0,
'Bob': 57.666666666666664}
%% Cell type:markdown id: tags:
### The Syntax of Comprehensions
%% Cell type:markdown id: tags:
![comprehensions.png](attachment:comprehensions.png)
%% Cell type:markdown id: tags:
For more reference, visit...
https://www.w3schools.com/python/python_lists_comprehension.asp
https://www.datacamp.com/community/tutorials/python-dictionary-comprehension
%% Cell type:markdown id: tags:
### Challenge: Recursion, Lambdas, and Comprehensions Together!
Sort the family tree as a list of people from youngest to oldest.
%% Cell type:markdown id: tags:
Expected Output:
```
[{'name': 'Jayden', 'age': 1},
{'name': 'Penelope', 'age': 24},
{'name': 'Skyla', 'age': 46},
{'name': 'Julia', 'age': 66},
{'name': 'Irine', 'age': 92},
{'name': 'Dot', 'age': 111}]
```
%% Cell type:code id: tags:
``` python
family_tree = {
"name": "Jayden",
"age": 1,
"mother": {
"name": "Penelope",
"age": 24,
"mother": {
"name": "Skyla",
"age": 46,
"mother": {
"name": "Julia",
"age": 66,
"mother": {
"name": "Irine",
"age": 92,
"mother": {
"name": "Dot",
"age": 111,
}
}
}
}
}
}
def get_person_info(person):
return {k: v for (k, v) in person.items() if k != 'mother'}
def get_people(person):
person_info = get_person_info(person)
if 'mother' not in person:
return [person_info]
else:
current_mother = person['mother']
return get_people(current_mother) + [person_info]
family_list = get_people(family_tree)
sorted(family_list, key=lambda d:d['age'])
```
%% Output
[{'name': 'Jayden', 'age': 1},
{'name': 'Penelope', 'age': 24},
{'name': 'Skyla', 'age': 46},
{'name': 'Julia', 'age': 66},
{'name': 'Irine', 'age': 92},
{'name': 'Dot', 'age': 111}]
%% Cell type:code id: tags:
``` python
# Warmup 1a: Sort this list by the length of each word using key=get_fruit_len
fruits = ["blackberry", "apple", "banana", "fig", "blueberry", "strawberry"]
def get_fruit_len(f):
pass
# TODO Sort the list of fruits
```
%% Cell type:code id: tags:
``` python
# Warmup 1b: Sort this list by the length of each word using a lambda
fruits = ["blackberry", "apple", "banana", "fig", "blueberry", "strawberry"]
```
%% Cell type:code id: tags:
``` python
# Warmup 2: Define: What is a lambda function?
```
%% Cell type:code id: tags:
``` python
# Warmup 3: Sort this dictionary by their total enrollment
enrollments = { "Wisconsin": 45540,
"Michigan": 47907,
"Illinois": 52331,
"Iowa": 30448,
"Minnesota": 52017,
"Ohio State": 61369,
"Northwestern": 22316}
```
%% Cell type:code id: tags:
``` python
# Warmup 4: Sort this list of dictionaries by 'name'
volunteers = [ {"name": "Sky", "hours": 53},
{"name":"Patrice", "hours": 72},
{"name":"Gabriella", "hours": 45},
{"name": "Jade", "hours": 62} ]
```
%% Cell type:code id: tags:
``` python
# Warmup 5: Sort this dictionary of lists by the length of the list
cities_by_county = {"Dane": ["Madison", "Sun Prairie", "Middleton", "Waunakee"],
"Milwaukee": ["Milwaukee", "West Allis", "Wauwatosa"],
"Rock": ["Janesville", "Beloit"],
"Waukesha": ["Brookfield"]}
```
%% Cell type:code id: tags:
``` python
# Warmup 6: Create a list of all fruits that contain 'berry'
fruits = ["blackberry", "apple", "banana", "fig", "blueberry", "strawberry"]
```
%% Cell type:markdown id: tags:
# Lecture 24: Iterators and Comprehensions
Learning Objectives:
- Create list and dictionary comprehensions
- Use the correct vocabulary to describe iteration
- iterable, sequence, iterator
- Determine if an object is an iterable, or if it is an iterator
- try to use iter() to determine if an object is an iterable
- try to use next() to determine if an object is an iterator
- Use iterator/iterable language to open and process files
%% Cell type:markdown id: tags:
## List Comprehensions
%% Cell type:code id: tags:
``` python
# Do we have a shorter way to complete Warmup 6?
# https://en.wikipedia.org/wiki/Code_golf
# Yes! Using List Comprehensions
fruits = ["blackberry", "apple", "banana", "fig", "blueberry", "strawberry"]
```
%% Cell type:code id: tags:
``` python
# What other ways could we filter our fruits list?
fruits = ["blackberry", "apple", "banana", "fig", "blueberry", "strawberry"]
# All fruits that contain berry (we just did this!)
# All fruits that start with the letter 'b'
# All fruits with short names
# The length of every fruit name
# ...
```
%% Cell type:code id: tags:
``` python
# All fruits that start with the letter 'b'
```
%% Cell type:code id: tags:
``` python
# All fruits with short names
```
%% Cell type:code id: tags:
``` python
# The length of every fruit name
```
%% Cell type:markdown id: tags:
### More List Comprehensions
%% Cell type:code id: tags:
``` python
# Convert these Fahrenheit temps to an int in Celsius using C = 5/9 * (F-32)
temps = [32, 45, 90, 212]
# First, write using a traditional for loop...
```
%% Cell type:code id: tags:
``` python
# Then, try writing it as a list comprehension!
```
%% Cell type:code id: tags:
``` python
# What if temps were strings?
```
%% Cell type:markdown id: tags:
### Even More List Comprehensions
%% Cell type:code id: tags:
``` python
# What ways could we filter this list of volunteers?
volunteers = [ {"name": "Sky", "hours": 53},
{"name": "Patrice", "hours": 72},
{"name": "Gabriella", "hours": 45},
{"name": "Jade", "hours": 62}
]
# Those that have volunteered atleast 60 hours
# Those with short names
# ...
```
%% Cell type:code id: tags:
``` python
# Those that have volunteered atleast 60 hours
```
%% Cell type:code id: tags:
``` python
# Those with short names
```
%% Cell type:code id: tags:
``` python
# What if we wanted to keep the name and hours?
```
%% Cell type:markdown id: tags:
### Dictionary Comprehensions
Same thing as a list comprehension, but with a key *and* value!
%% Cell type:code id: tags:
``` python
# Generate a dictionary of numbers and their squares! e.g. {1: 1, 2: 4, 3: 9, 4: 16, ...}
nums = [1, 2, 3, 4, 5, 6, 7]
square_mapping_dict = ...
square_mapping_dict
```
%% Cell type:code id: tags:
``` python
# What ways could we filter this dictionary of people's scores?
scores_dict = {"Bob": [18, 72, 83],
"Cindy" : [27, 11, 55, 73, 87],
"Alice": [16, 33, 42, 89, 90],
"Meena": [39, 93, 9, 3, 55, 72, 19]}
# A dictionary of how many scores each player has
# A dictionary of everyone's highest score
# A dictionary of everyone's average score
# ...
```
%% Cell type:code id: tags:
``` python
# Tip: We can use "tuple unpacking" in our for loop!
# An old fashioned for loop...
new_scores_dict = {}
for (player, scores) in scores_dict.items():
new_scores_dict[player] = len(scores)
new_scores_dict
```
%% Cell type:code id: tags:
``` python
# A dictionary of how many scores each player has
```
%% Cell type:code id: tags:
``` python
# A dictionary of everyone's highest score
```
%% Cell type:code id: tags:
``` python
# A dictionary of everyone's average score
```
%% Cell type:code id: tags:
``` python
# Challenge: A sorted dictionary of everyone's average score.
# Hint: Convert the above dictionary to a list of tuples,
# sort based on the score, and turn back into a dict.
```
%% Cell type:markdown id: tags:
### The Syntax of Comprehensions
%% Cell type:markdown id: tags:
![comprehensions.png](attachment:comprehensions.png)
%% Cell type:markdown id: tags:
For more reference, visit...
https://www.w3schools.com/python/python_lists_comprehension.asp
https://www.datacamp.com/community/tutorials/python-dictionary-comprehension
%% Cell type:markdown id: tags:
### Challenge: Recursion, Lambdas, and Comprehensions Together!
Sort the family tree as a list of people from youngest to oldest.
%% Cell type:markdown id: tags:
Expected Output:
```
[{'name': 'Jayden', 'age': 1},
{'name': 'Penelope', 'age': 24},
{'name': 'Skyla', 'age': 46},
{'name': 'Julia', 'age': 66},
{'name': 'Irine', 'age': 92},
{'name': 'Dot', 'age': 111}]
```
%% Cell type:code id: tags:
``` python
family_tree = {
"name": "Jayden",
"age": 1,
"mother": {
"name": "Penelope",
"age": 24,
"mother": {
"name": "Skyla",
"age": 46,
"mother": {
"name": "Julia",
"age": 66,
"mother": {
"name": "Irine",
"age": 92,
"mother": {
"name": "Dot",
"age": 111,
}
}
}
}
}
}
def get_person_info(person):
pass # hint: use a dictionary comprehension
def get_people(person):
person_info = get_person_info(person)
if ???: # base case
return [person_info]
else: # recursive case
current_mother = person['mother']
return ???
family_list = get_people(family_tree)
??? # hint: sort the family_list using a lambda
```
%% Cell type:code id:7c56f9e4 tags:
``` python
words = ["pineapple", "mango", "quince", "blueberry", "orange"]
```
%% Cell type:code id:15652478 tags:
``` python
# This is a list of strings.
```
%% Cell type:code id:817f579f tags:
``` python
#A.q1 Use comprehension to create a list of the words that contain "o"
[w for w in words if "o" in w]
```
%% Output
['mango', 'orange']
%% Cell type:code id:4dd182dd tags:
``` python
#A.q2 Use comprehension to create a list of words that have a length > 7
[x for x in words if len(x) > 7]
```
%% Output
['pineapple', 'blueberry']
%% Cell type:code id:d3712c7a tags:
``` python
#A.q3 Use comprehension to create a list of integers that represent the length of each word
[len(word) for word in words]
```
%% Output
[9, 5, 6, 9, 6]
%% Cell type:code id:6126ab6e tags:
``` python
#A.q4 Use comprehension to create a list of words that end with "e"
[w for w in words if w.endswith("e")]
```
%% Output
['pineapple', 'quince', 'orange']
%% Cell type:code id:bcbab6a8 tags:
``` python
heart_rates = {"Micah": [67, 59, 84, 88],
"Briana": [59, 73, 67, 80, 79],
"Jaren": [67, 84, 71, 68 , 70]}
```
%% Cell type:code id:3dd3b3fc tags:
``` python
# This is a dictionary mapping each string to a list of ints.
```
%% Cell type:code id:14983b5f tags:
``` python
#B.q1 Use comprehension to create a list of the names
[p for p in heart_rates]
# or using tuple unpacking
# [p for (p, hrs) in heart_rates.items()]
```
%% Output
['Micah', 'Briana', 'Jaren']
%% Cell type:code id:f080b33a tags:
``` python
#B.q2 Use comprehension to create a dictionary where the key is the same key, but the value is the min of each list
{p: min(hrs) for (p, hrs) in heart_rates.items()}
# or NOT using tuple unpacking
# {p: min(heart_rates[p]) for p in heart_rates}
```
%% Output
{'Micah': 59, 'Briana': 59, 'Jaren': 67}
%% Cell type:code id:52198994 tags:
``` python
#B.q3 Use comprehension to create a dictionary where the key is the same key, but the value is the average of each list
{p: sum(hrs) / len(hrs) for (p, hrs) in heart_rates.items()}
# or NOT using tuple unpacking
# {p: sum(heart_rates[p]) / len(heart_rates[p]) for p in heart_rates}
```
%% Output
{'Micah': 74.5, 'Briana': 71.6, 'Jaren': 72.0}
%% Cell type:code id:b4c58448 tags:
``` python
player_stats = [
{"name": "Rina", "goals": 17, "position": "Midfield"},
{"name": "Charlie", "goals": 6, "position": "Defender"},
{"name": "Heather", "goals": 20, "position": "Midfield"}
]
```
%% Cell type:code id:29442f92 tags:
``` python
# This is a list of dictionaries that map 'name' to a string, 'goals' to an int, and 'position' to a string.
```
%% Cell type:code id:cc6b8524 tags:
``` python
#C.q1 Use comprehension to create a list of names of people who scored >10 goals
[person['name'] for person in player_stats if person['goals'] > 10]
```
%% Output
['Rina', 'Heather']
%% Cell type:code id:58abdf9e tags:
``` python
#C.q2 Use comprehension to create a list of all unique positions
# We have list and dict comprehension, but also Set comprehension!
list({person['position'] for person in player_stats})
```
%% Output
['Midfield', 'Defender']
%% Cell type:code id:7c56f9e4 tags:
``` python
words = ["pineapple", "mango", "quince", "blueberry", "orange"]
```
%% Cell type:code id:817f579f tags:
``` python
#A.q1 Use comprehension to create a list of the words that contain "o"
```
%% Cell type:code id:4dd182dd tags:
``` python
#A.q2 Use comprehension to create a list of words that have a length > 7
```
%% Cell type:code id:d3712c7a tags:
``` python
#A.q3 Use comprehension to create a list of integers that represent the length of each word
```
%% Cell type:code id:6126ab6e tags:
``` python
#A.q4 Use comprehension to create a list of words that end with "e"
```
%% Cell type:code id:bcbab6a8 tags:
``` python
heart_rates = {"Micah": [67, 59, 84, 88],
"Briana": [59, 73, 67, 80, 79],
"Jaren": [67, 84, 71, 68 , 70]}
```
%% Cell type:code id:14983b5f tags:
``` python
#B.q1 Use comprehension to create a list of the names
```
%% Cell type:code id:f080b33a tags:
``` python
#B.q2 Use comprehension to create a dictionary where the key is the same key, but the value is the min of each list
```
%% Cell type:code id:52198994 tags:
``` python
#B.q3 Use comprehension to create a dictionary where the key is the same key, but the value is the average of each list
```
%% Cell type:code id:b4c58448 tags:
``` python
player_stats = [
{"name": "Rina", "goals": 17, "position": "Midfield"},
{"name": "Charlie", "goals": 6, "position": "Defender"},
{"name": "Heather", "goals": 20, "position": "Midfield"}
]
```
%% Cell type:code id:cc6b8524 tags:
``` python
#C.q1 Use comprehension to create a list of names of people who scored >10 goals
```
%% Cell type:code id:58abdf9e tags:
``` python
#C.q2 Use comprehension to create a list of all unique positions
```
%% Cell type:code id: tags:
``` python
import time
```
%% Cell type:code id: tags:
``` python
# Warmup: Review Worksheet Exercises.
```
%% Cell type:code id: tags:
``` python
# Warmup:
# Run this program and think of 2 different kinds of inputs that would crash it.
# Name the Runtime errors that occurred here:
# ...Entering a slice count of 0....divide by 0 ZeroDivisionError
# ...Entering non-numbers ValueError
# ...Entering only 1 number or no comma IndexError
# Then, think of other inputs that will give Semantic Errors
# ...Entering a negative number
import math
def pizza_size(radius):
# What do we assume is true here?
return (radius ** 2) * math.pi # SemanticError
def slice_size(radius, slice_count):
# What could go wrong here?
total_size = pizza_size(radius)
return total_size * (1 / slice_count) # ZeroDivisionError
# What could go wrong here?
args = input("Enter pizza diameter(inches), slice count: ")
args = args.split(',')
radius = float(args[0].strip()) / 2 # ValueError
slices = int(args[1].strip()) # IndexError, ValueError
size = slice_size(radius, slices)
print('Each pizza slice will be {} square inches'.format(size))
```
%% Cell type:markdown id: tags:
### Lecture 25: Error Handling
**Learing Objectives:**
- Explain the purpose of assert statements, try/except blocks, and raise statements.
- Use an assert statement to force a program to crash, and trace code that uses assert.
- Use try/except blocks to catch runtime errors and deal with them
- by specifying the exception(s) caught
- by using the exception object
- Use the raise statement to raise an exception that may be caught in another part of the program
- Hand trace code that uses assert, try/except blocks and raise statements
%% Cell type:markdown id: tags:
### Being 'Assert'ive
`assert` makes code 'fail fast' rather than continuing with bad data. This is useful because we would prefer to have runtime errors over semantic (thinking) errors.
An `assert` statement takes a boolean condition, e.g. `assert my_list != []` would assert that the list is not empty.
If the assert statement is True, nothing happens. If the assert statement is False, a runtime error occurs.
%% Cell type:code id: tags:
``` python
age = int(input("Enter your age: "))
assert age >= 0
print("In five years, you will be", age + 5, "years old")
```
%% Cell type:code id: tags:
``` python
# You try!
# In pizza_size, assert that the radius is positive.
# In slice_size assert that slice_count is positive.
import math
def pizza_size(radius):
assert radius > 0
return (radius ** 2) * math.pi
def slice_size(radius, slice_count):
assert slice_count >= 1
total_size = pizza_size(radius)
return total_size * (1 / slice_count)
args = input("Enter pizza diameter(inches), slice count: ")
args = args.split(',')
radius = float(args[0].strip()) / 2
slices = int(args[1].strip())
size = slice_size(radius, slices)
print('Each pizza slice will be {} square inches'.format(size))
```
%% Cell type:markdown id: tags:
### Use `try`/`except` blocks to "catch" runtime errors
`assert` isn't always the prettiest for the user -- their program crashes!
Often, we prefer to use `try` and `except`. `try` and `except` blocks come in pairs. Python tries to run the code in the `try` block, but if there’s an exception, it jumps to the `except` block -- it does not crash! We call this "catching" the exception. If there is no exception, the `except` block does not run.
%% Cell type:code id: tags:
``` python
try:
print("2 inverse is", 1/2)
print("1 inverse is", 1/1)
print("0 inverse is", 1/0) # this line results in a RuntimeError
print("-1 inverse is", 1/-1)
print("-2 inverse is", 1/-2)
except:
print("Something bad happened :(")
print("Just like ifs, we join here!")
```
%% Cell type:code id: tags:
``` python
# You try! Catch the error before the program crashes.
# For this example, do NOT use an if statement!
pizza_slices = 8
try:
num_people = int(input("Enter a number of people to divide the pizza among: "))
assert num_people > 0
pizza_per_person = pizza_slices / num_people
print(pizza_per_person, "slices per person.")
except:
print("Please use a valid number.")
```
%% Cell type:markdown id: tags:
### Being Descriptive
We can be more descriptive by saying `except Exception as e` and printing out information with `e`
%% Cell type:code id: tags:
``` python
try:
print("2 inverse is", 1/2)
print("1 inverse is", 1/1)
print("0 inverse is", 1/0) # this line results in a RuntimeError
print("-1 inverse is", 1/-1)
print("-2 inverse is", 1/-2)
except Exception as e:
print("Something bad happened :(")
print(type(e))
print(str(e))
```
%% Cell type:code id: tags:
``` python
# Add a try/catch block to handle all errors
# Be descriptive, print out the error type and message.
import math
def pizza_size(radius):
assert radius > 0
return (radius ** 2) * math.pi
def slice_size(radius, slice_count):
assert slice_count >= 1
total_size = pizza_size(radius)
return total_size * (1 / slice_count)
while(True):
args = input("Enter pizza diameter(inches), slice count: ")
args = args.split(',')
try:
radius = float(args[0].strip()) / 2
slices = int(args[1].strip())
size = slice_size(radius, slices)
print('Each pizza slice will be {} square inches'.format(size))
except Exception as e:
print("Something went wrong!")
print(type(e))
print(str(e))
```
%% Cell type:markdown id: tags:
### Nested Exceptions
Exceptions can be thrown from any function. If that function cannot handle the exception, the exception goes to the calling function. If that function cannot handle the exception, to its calling function. If no calling function can handle the exception, the program crashes.
%% Cell type:code id: tags:
``` python
def cole():
print("Cole: Hello! :)")
cust_happy = input("Cole: Are you having a pleasent shopping experience?")
assert cust_happy.lower() == 'y'
print("Cole: Great! :)")
def matt():
print("At Matt's store...")
cole()
def pig_wig_corp():
while(True):
print("At the pig wig...")
matt()
time.sleep(5)
pig_wig_corp()
```
%% Cell type:markdown id: tags:
We can choose where to handle an exception, e.g. defer all complaints to corporate.
%% Cell type:code id: tags:
``` python
def cole():
print("Cole: Hello! :)")
cust_happy = input("Cole: Are you having a pleasent shopping experience?")
assert cust_happy.lower() == 'y'
print("Cole: Great! :)")
def matt():
print("At Matt's store...")
cole()
def pig_wig_corp():
while(True):
print("At the pig wig...")
try:
matt()
except Exception as e:
print("Corp: We are sorry to hear this.")
print("Err msg:", str(e))
print("Err type:", type(e))
time.sleep(5)
pig_wig_corp()
```
%% Cell type:markdown id: tags:
... or handle them ourselves ...
%% Cell type:code id: tags:
``` python
def cole():
try:
print("Cole: Hello! :)")
cust_happy = input("Cole: Are you having a pleasent shopping experience?")
assert cust_happy.lower() == 'y'
print("Cole: Great! :)")
except Exception as e:
print("Cole: Dang that's rough")
def matt():
print("At Matt's store...")
cole()
def pig_wig_corp():
while(True):
print("At the pig wig...")
try:
matt()
except Exception as e:
print("Corp: We are sorry to hear this.")
print("Err msg:", str(e))
print("Err type:", type(e))
time.sleep(5)
pig_wig_corp()
```
%% Cell type:markdown id: tags:
... or somewhere in between!
%% Cell type:markdown id: tags:
### `raise` Our Own Errors
Rather than using `assert` we can also `raise` an error. As we can see by `type(e)`, there are different types of errors in Python. These form a hierarchy [(see here)](https://docs.python.org/3/library/exceptions.html). It helps to know some common exceptions, but you don't need to memorize them.
%% Cell type:code id: tags:
``` python
def cole():
print("Cole: Hello! :)")
cust_happy = input("Cole: Are you having a pleasent shopping experience?")
if cust_happy.lower() != 'y':
raise FutureWarning("This customer may not return in the future!")
print("Cole: Great! :)")
def matt():
print("At Matt's store...")
cole()
def pig_wig_corp():
while(True):
print("At the pig wig...")
try:
matt()
except Exception as e:
print("Corp: We are sorry to hear this.")
print("Err msg:", str(e))
print("Err type:", type(e))
time.sleep(5)
pig_wig_corp()
```
%% Cell type:markdown id: tags:
Let's check if the customer is happy and if they have found everything they needed.
- If they are not happy, `raise` a `FutureWarning`. Corporate can handle this.
- If they have not found everything they needed, `raise` a `ResourceWarning`. Matt can handle this.
%% Cell type:code id: tags:
``` python
def cole():
print("Cole: Hello! :)")
cust_happy = input("Cole: Are you having a pleasent shopping experience?")
if cust_happy.lower() != 'y':
raise FutureWarning("This customer may not return in the future!")
cust_found = input("Cole: Did you find everything that you needed?")
if cust_found.lower() != 'y':
raise ResourceWarning("We are running out of resources!")
print("Cole: Great! :)")
def matt():
print("At Matt's store...")
try:
cole()
except Exception as e: # ALMOST correct....
print("Matt: I'll order some more!")
def pig_wig_corp():
while(True):
print("At the pig wig...")
try:
matt()
except Exception as e:
print("Corp: We are sorry to hear this.")
print("Err msg:", str(e))
print("Err type:", type(e))
time.sleep(5)
pig_wig_corp()
```
%% Cell type:markdown id: tags:
What's wrong with the above function? Fix it below.
%% Cell type:code id: tags:
``` python
def cole():
print("Cole: Hello! :)")
cust_happy = input("Cole: Are you having a pleasent shopping experience?")
if cust_happy.lower() != 'y':
raise FutureWarning("This customer may not return in the future!")
cust_found = input("Cole: Did you find everything that you needed?")
if cust_found.lower() != 'y':
raise ResourceWarning("We are running out of resources!")
print("Cole: Great! :)")
def matt():
print("At Matt's store...")
try:
cole()
except ResourceWarning as e:
print("Matt: I'll order some more!")
def pig_wig_corp():
while(True):
print("At the pig wig...")
try:
matt()
except Exception as e:
print("Corp: We are sorry to hear this.")
print("Err msg:", str(e))
print("Err type:", type(e))
time.sleep(5)
pig_wig_corp()
```
%% Cell type:markdown id: tags:
Let's also ask the customer if they are feeling healthy. If not, we should `raise` a `UserWarning` and Matt should ask them to leave the store.
%% Cell type:code id: tags:
``` python
def cole():
print("Cole: Hello! :)")
cust_happy = input("Cole: Are you having a pleasent shopping experience?")
if cust_happy.lower() != 'y':
raise FutureWarning("This customer may not return in the future!")
cust_found = input("Cole: Did you find everything that you needed?")
if cust_found.lower() != 'y':
raise ResourceWarning("We are running out of resources!")
cust_healthy = input("Cole: Are you feeling healthy today?")
if cust_healthy.lower() != 'y':
raise UserWarning("The customer is feeling sick...")
print("Cole: Great! :)")
def matt():
print("At Matt's store...")
try:
cole()
except ResourceWarning as rw:
print("Matt: I'll order some more!")
except UserWarning as uw:
print("Matt: Please leave the store :(")
def pig_wig_corp():
while(True):
print("At the pig wig...")
try:
matt()
except Exception as e:
print("Corp: We are sorry to hear this.")
print("Err msg:", str(e))
print("Err type:", type(e))
time.sleep(5)
pig_wig_corp()
```
%% Cell type:code id: tags:
``` python
# Consider the code below and answer the following questions...
# In your own words, describe what the code does.
# There is a random chance each one of our "flaky" functions break,
# and we attempt to catch the exceptions as they happen.
# In a single iteration, can a FloatingPointError and OverflowError be thrown?
# No, since these are in the same try/catch block, as soon as there is an exception,
# we will skip to the "except" block. Either one (or neither) may be thrown,
# but not both.
# In a single iteration, can a OSError follow an OverflowError?
# Yes. Although we catch the overflow error if it happens,
# there is a 1% chance an OSError follows. They are not in the
# same try/except block.
# Are there any error(s) we are not catching? If so, name them.
# We are not catching an OSError as it is not inside a try/catch.
# We are also not catching a PermissionError as neither the type
# nor supertype is in the except block.
# Are there any error(s) we are catching but not raising?
# Yes, FileExistsError is not raised by anything.
```
%% Cell type:code id: tags:
``` python
import random
import time
def flaky_math_func1():
if(random.random() < .5):
raise FloatingPointError("Something went wrong doing some float math!")
def flaky_math_func2():
if(random.random() < .5):
raise OverflowError("Something went wrong doing some big math!")
def flaky_os_func():
if(random.random() < .01):
raise OSError("Something went wrong in the OS!")
def flaky_impl_func():
if(random.random() < .05):
raise NotImplementedError("Something went wrong in the implementation!")
def flaky_perm_func():
if(random.random() < .2):
raise PermissionError("I don't have permission to do that!")
while(True):
print("Beginning the flaky functions!")
try:
flaky_math_func1()
flaky_math_func2()
except ArithmeticError as e:
print("Phew! I avoided a", type(e))
flaky_os_func()
try:
flaky_impl_func()
flaky_perm_func()
except (RuntimeError, FileExistsError) as e:
print("Phew! I avoided a", type(e))
print("End of flaky functions!")
print()
time.sleep(10) # wait 10 seconds, give time to read the output.
```
%% Cell type:markdown id: tags:
### A Word on Hierarchy
All dogs are animals, but not all animals are dogs.
All ZeroDivisionErrors are ArithmeticErrors, but not all ArithmeticErrors are ZeroDivisionErrors.
%% Cell type:markdown id: tags:
![1_iP78XqAbkntOuzbHCoiubg.png](attachment:1_iP78XqAbkntOuzbHCoiubg.png)
%% Cell type:markdown id: tags:
[Source](https://levelup.gitconnected.com/java-classes-and-objects-a312db4bc785) (yes this is a Java resource -- but applicable to MANY programming languages!)
%% Cell type:code id: tags:
``` python
import time
```
%% Cell type:code id: tags:
``` python
# Warmup: Review Worksheet Exercises.
```
%% Cell type:code id: tags:
``` python
# Warmup:
# Run this program and think of 2 different kinds of inputs that would crash it.
# Name the Runtime errors that occurred here:
#
# Then, think of other inputs that will give Semantic Errors
#
import math
def pizza_size(radius):
# What do we assume is true here?
return (radius ** 2) * math.pi
def slice_size(radius, slice_count):
# What could go wrong here?
total_size = pizza_size(radius)
return total_size * (1 / slice_count)
# What could go wrong here?
args = input("Enter pizza diameter(inches), slice count: ")
args = args.split(',')
radius = float(args[0].strip()) / 2
slices = int(args[1].strip())
size = slice_size(radius, slices)
print('Each pizza slice will be {} square inches'.format(size))
```
%% Cell type:markdown id: tags:
### Lecture 25: Error Handling
**Learing Objectives:**
- Explain the purpose of assert statements, try/except blocks, and raise statements.
- Use an assert statement to force a program to crash, and trace code that uses assert.
- Use try/except blocks to catch runtime errors and deal with them
- by specifying the exception(s) caught
- by using the exception object
- Use the raise statement to raise an exception that may be caught in another part of the program
- Hand trace code that uses assert, try/except blocks and raise statements
%% Cell type:markdown id: tags:
### Being 'Assert'ive
`assert` makes code 'fail fast' rather than continuing with bad data. This is useful because we would prefer to have runtime errors over semantic (thinking) errors.
An `assert` statement takes a boolean condition, e.g. `assert my_list != []` would assert that the list is not empty.
If the assert statement is True, nothing happens. If the assert statement is False, a runtime error occurs.
%% Cell type:code id: tags:
``` python
age = int(input("Enter your age: "))
# TODO Assert age is positive
print("In five years, you will be", age + 5, "years old")
```
%% Cell type:code id: tags:
``` python
# You try!
# In pizza_size, assert that the radius is positive.
# In slice_size assert that slice_count is positive.
import math
def pizza_size(radius):
return (radius ** 2) * math.pi
def slice_size(radius, slice_count):
total_size = pizza_size(radius)
return total_size * (1 / slice_count)
args = input("Enter pizza diameter(inches), slice count: ")
args = args.split(',')
radius = float(args[0].strip()) / 2
slices = int(args[1].strip())
size = slice_size(radius, slices)
print('Each pizza slice will be {} square inches'.format(size))
```
%% Cell type:markdown id: tags:
### Use `try`/`except` blocks to "catch" runtime errors
`assert` isn't always the prettiest for the user -- their program crashes!
Often, we prefer to use `try` and `except`. `try` and `except` blocks come in pairs. Python tries to run the code in the `try` block, but if there’s an exception, it jumps to the `except` block -- it does not crash! We call this "catching" the exception. If there is no exception, the `except` block does not run.
%% Cell type:code id: tags:
``` python
try:
print("2 inverse is", 1/2)
print("1 inverse is", 1/1)
print("0 inverse is", 1/0) # this line results in a RuntimeError
print("-1 inverse is", 1/-1)
print("-2 inverse is", 1/-2)
except:
print("Something bad happened :(")
print("Just like ifs, we join here!")
```
%% Cell type:code id: tags:
``` python
# You try! Catch the error before the program crashes.
# For this example, do NOT use an if statement!
pizza_slices = 8
num_people = int(input("Enter a number of people to divide the pizza among: "))
pizza_per_person = pizza_slices / num_people
print(pizza_per_person, "slices per person.")
```
%% Cell type:markdown id: tags:
### Being Descriptive
We can be more descriptive by saying `except Exception as e` and printing out information with `e`
%% Cell type:code id: tags:
``` python
try:
print("2 inverse is", 1/2)
print("1 inverse is", 1/1)
print("0 inverse is", 1/0) # this line results in a RuntimeError
print("-1 inverse is", 1/-1)
print("-2 inverse is", 1/-2)
except Exception as e:
print("Something bad happened :(")
print(type(e))
print(str(e))
```
%% Cell type:code id: tags:
``` python
# Add a try/catch block to handle all errors
# Be descriptive, print out the error type and message.
import math
def pizza_size(radius):
assert radius > 0
return (radius ** 2) * math.pi
def slice_size(radius, slice_count):
assert slice_count >= 1
total_size = pizza_size(radius)
return total_size * (1 / slice_count)
while(True):
args = input("Enter pizza diameter(inches), slice count: ")
args = args.split(',')
radius = float(args[0].strip()) / 2
slices = int(args[1].strip())
size = slice_size(radius, slices)
print('Each pizza slice will be {} square inches'.format(size))
```
%% Cell type:markdown id: tags:
### Nested Exceptions
Exceptions can be thrown from any function. If that function cannot handle the exception, the exception goes to the calling function. If that function cannot handle the exception, to its calling function. If no calling function can handle the exception, the program crashes.
%% Cell type:code id: tags:
``` python
def cole():
print("Cole: Hello! :)")
cust_happy = input("Cole: Are you having a pleasent shopping experience?")
assert cust_happy.lower() == 'y'
print("Cole: Great! :)")
def matt():
print("At Matt's store...")
cole()
def pig_wig_corp():
while(True):
print("At the pig wig...")
matt()
time.sleep(5)
pig_wig_corp()
```
%% Cell type:markdown id: tags:
We can choose where to handle an exception, e.g. defer all complaints to corporate.
%% Cell type:code id: tags:
``` python
def cole():
print("Cole: Hello! :)")
cust_happy = input("Cole: Are you having a pleasent shopping experience?")
assert cust_happy.lower() == 'y'
print("Cole: Great! :)")
def matt():
print("At Matt's store...")
cole()
def pig_wig_corp():
while(True):
print("At the pig wig...")
try:
matt()
except Exception as e:
print("Corp: We are sorry to hear this.")
print("Err msg:", str(e))
print("Err type:", type(e))
time.sleep(5)
pig_wig_corp()
```
%% Cell type:markdown id: tags:
... or handle them ourselves ...
%% Cell type:code id: tags:
``` python
def cole():
try:
print("Cole: Hello! :)")
cust_happy = input("Cole: Are you having a pleasent shopping experience?")
assert cust_happy.lower() == 'y'
print("Cole: Great! :)")
except Exception as e:
print("Cole: Dang that's rough")
def matt():
print("At Matt's store...")
cole()
def pig_wig_corp():
while(True):
print("At the pig wig...")
try:
matt()
except Exception as e:
print("Corp: We are sorry to hear this.")
print("Err msg:", str(e))
print("Err type:", type(e))
time.sleep(5)
pig_wig_corp()
```
%% Cell type:markdown id: tags:
... or somewhere in between!
%% Cell type:markdown id: tags:
### `raise` Our Own Errors
Rather than using `assert` we can also `raise` an error. As we can see by `type(e)`, there are different types of errors in Python. These form a hierarchy [(see here)](https://docs.python.org/3/library/exceptions.html). It helps to know some common exceptions, but you don't need to memorize them.
%% Cell type:code id: tags:
``` python
def cole():
print("Cole: Hello! :)")
cust_happy = input("Cole: Are you having a pleasent shopping experience?")
if cust_happy.lower() != 'y':
raise FutureWarning("This customer may not return in the future!")
print("Cole: Great! :)")
def matt():
print("At Matt's store...")
cole()
def pig_wig_corp():
while(True):
print("At the pig wig...")
try:
matt()
except Exception as e:
print("Corp: We are sorry to hear this.")
print("Err msg:", str(e))
print("Err type:", type(e))
time.sleep(5)
pig_wig_corp()
```
%% Cell type:markdown id: tags:
Let's check if the customer is happy and if they have found everything they needed.
- If they are not happy, `raise` a `FutureWarning`. Corporate can handle this.
- If they have not found everything they needed, `raise` a `ResourceWarning`. Matt can handle this.
%% Cell type:code id: tags:
``` python
def cole():
print("Cole: Hello! :)")
cust_happy = input("Cole: Are you having a pleasent shopping experience?")
if cust_happy.lower() != 'y':
raise FutureWarning("This customer may not return in the future!")
cust_found = input("Cole: Did you find everything that you needed?")
if cust_found.lower() != 'y':
raise ResourceWarning("We are running out of resources!")
print("Cole: Great! :)")
def matt():
print("At Matt's store...")
try:
cole()
except Exception as e: # ALMOST correct....
print("Matt: I'll order some more!")
def pig_wig_corp():
while(True):
print("At the pig wig...")
try:
matt()
except Exception as e:
print("Corp: We are sorry to hear this.")
print("Err msg:", str(e))
print("Err type:", type(e))
time.sleep(5)
pig_wig_corp()
```
%% Cell type:markdown id: tags:
What's wrong with the above function? Fix it below.
%% Cell type:code id: tags:
``` python
```
%% Cell type:markdown id: tags:
Let's also ask the customer if they are feeling healthy. If not, we should `raise` a `UserWarning` and Matt should ask them to leave the store.
%% Cell type:code id: tags:
``` python
def cole():
print("Cole: Hello! :)")
cust_happy = input("Cole: Are you having a pleasent shopping experience?")
if cust_happy.lower() != 'y':
raise FutureWarning("This customer may not return in the future!")
cust_found = input("Cole: Did you find everything that you needed?")
if cust_found.lower() != 'y':
raise ResourceWarning("We are running out of resources!")
# TODO: Ask the customer if they are feeling healthy.
print("Cole: Great! :)")
def matt():
print("At Matt's store...")
try:
cole()
except ResourceWarning as rw:
print("Matt: I'll order some more!")
except UserWarning as uw:
print("Matt: Please leave the store :(")
def pig_wig_corp():
while(True):
print("At the pig wig...")
try:
matt()
except Exception as e:
print("Corp: We are sorry to hear this.")
print("Err msg:", str(e))
print("Err type:", type(e))
time.sleep(5)
pig_wig_corp()
```
%% Cell type:code id: tags:
``` python
# Consider the code below and answer the following questions...
# In your own words, describe what the code does.
#
# In a single iteration, can a FloatingPointError and OverflowError be thrown?
#
# In a single iteration, can a OSError follow an OverflowError?
#
# Are there any error(s) we are not catching? If so, name them.
#
# Are there any error(s) we are catching but not raising?
#
```
%% Cell type:code id: tags:
``` python
import random
import time
def flaky_math_func1():
if(random.random() < .5):
raise FloatingPointError("Something went wrong doing some float math!")
def flaky_math_func2():
if(random.random() < .5):
raise OverflowError("Something went wrong doing some big math!")
def flaky_os_func():
if(random.random() < .01):
raise OSError("Something went wrong in the OS!")
def flaky_impl_func():
if(random.random() < .05):
raise NotImplementedError("Something went wrong in the implementation!")
def flaky_perm_func():
if(random.random() < .2):
raise PermissionError("I don't have permission to do that!")
while(True):
print("Beginning the flaky functions!")
try:
flaky_math_func1()
flaky_math_func2()
except ArithmeticError as e:
print("Phew! I avoided a", type(e))
flaky_os_func()
try:
flaky_impl_func()
flaky_perm_func()
except (RuntimeError, FileExistsError) as e:
print("Phew! I avoided a", type(e))
print("End of flaky functions!")
print()
time.sleep(10) # wait 10 seconds, give time to read the output.
```
%% Cell type:markdown id: tags:
### A Word on Hierarchy
All dogs are animals, but not all animals are dogs.
All ZeroDivisionErrors are ArithmeticErrors, but not all ArithmeticErrors are ZeroDivisionErrors.
%% Cell type:markdown id: tags:
![1_iP78XqAbkntOuzbHCoiubg.png](attachment:1_iP78XqAbkntOuzbHCoiubg.png)
%% Cell type:markdown id: tags:
[Source](https://levelup.gitconnected.com/java-classes-and-objects-a312db4bc785) (yes this is a Java resource -- but applicable to MANY programming languages!)
Source diff could not be displayed: it is too large. Options to address this: view the blob.
Source diff could not be displayed: it is too large. Options to address this: view the blob.
{
"Cole": 2
}
\ No newline at end of file