# Please always run this code block.
%config InteractiveShell.ast_node_interactivity="none"
%pip install termcolor
import base64
import termcolor
# Defines print_globals
def f(globals, locals):
import base64
code="ZGVmIG1ha2VfcHJpbnRfbG9jYWxzKCk6IAogICAgIyBJbiBhIGZ1bmN0aW9uIHRvIHByZXZlbnQgbG9jYWxzIGFuZCBpbXBvcnRzIGZyb20gbGVha2luZy4KICAgIGdsb2JhbCBtYWtlX3ByaW50X2xvY2FscwogICAgZGVsIG1ha2VfcHJpbnRfbG9jYWxzICAjIE9ubHkgcnVuIHRoaXMgZnVuY3Rpb24gb25jZS4KCiAgICBpbXBvcnQgSVB5dGhvbgogICAgaW1wb3J0IGFzdAogICAgaW1wb3J0IGluc3BlY3QKCiAgICBjbGFzcyBWaXNpdG9yKGFzdC5Ob2RlVmlzaXRvcik6CiAgICAgICAgZGVmIF9faW5pdF9fKHNlbGYpOgogICAgICAgICAgICBzZWxmLnZhcmlhYmxlcyA9IHNldCgpCiAgICAgICAgZGVmIHZpc2l0X05hbWUoc2VsZiwgbmFtZSk6CiAgICAgICAgICAgIHNlbGYudmFyaWFibGVzLmFkZChuYW1lLmlkKQogICAgICAgICMgVE9ETzogUG9zc2libHkgZGV0ZWN0IHdoZXRoZXIgdmFyaWFibGVzIGFyZSBhc3NpZ25lZCB0by4KCiAgICBBTExPV19UWVBFUyA9IFtpbnQsIGZsb2F0LCBzdHIsIGJvb2wsIGxpc3QsIGRpY3QsIHR1cGxlLCByYW5nZV0KICAgIGRlZiBmaWx0ZXJfdmFyaWFibGVzKHZhcmlhYmxlcywgbG9jYWxzKToKICAgICAgICBmb3IgdiBpbiB2YXJpYWJsZXM6CiAgICAgICAgICAgIGlmIHYgaW4gbG9jYWxzIGFuZCB0eXBlKGxvY2Fsc1t2XSkgaW4gQUxMT1dfVFlQRVM6CiAgICAgICAgICAgICAgICB5aWVsZCB2CiAgCiAgICAjIFVuZm9ydHVuYXRlbHksIHRoZXJlIGRvZXNuJ3Qgc2VlbSB0byBiZSBhIHN1cHBvcnRlZCB3YXkgb2YgZ2V0dGluZwogICAgIyB0aGUgY3VycmVudCBjZWxsJ3MgY29kZSB2aWEgdGhlIHB1YmxpYyBJUHl0aG9uIEFQSXMuIEhvd2V2ZXIsIGJlY2F1c2UKICAgICMgd2UgYXJlIGdldHRpbmcgY2FsbGVkIGZyb20gSVB5dGhvbiBpdHNlbGYgYW5kIHdlIGFyZSBhbHJlYWR5IGluc3BlY3RpbmcKICAgICMgdGhlIHN0YWNrdHJhY2UsIHdlIG1pZ2h0IGFzIHdlbGwganVzdCBwZWVrIGludG8gaXRzIGZyYW1lLi4uCiAgICBpZiBJUHl0aG9uLl9fdmVyc2lvbl9fID09ICI1LjUuMCI6CiAgICAgICAgIyBjb2xhYgogICAgICAgIGRlZiBnZXRfYXN0KGZyYW1lKToKICAgICAgICAgICAgcmV0dXJuIGFzdC5Nb2R1bGUoZnJhbWUuZl9iYWNrLmZfYmFjay5mX2xvY2Fsc1sibm9kZWxpc3QiXSkKICAgICAgICBkZWYgZmluZF9sb2NhbHMoZnJhbWUpOgogICAgICAgICAgICByZXR1cm4gZnJhbWUuZl9sb2NhbHMKICAgICAgICBkZWYgYXRfdG9wX2xldmVsKGZyYW1lKToKICAgICAgICAgICAgcmV0dXJuIGZyYW1lLmZfYmFjay5mX2NvZGUuY29fZmlsZW5hbWUuZW5kc3dpdGgoIklQeXRob24vY29yZS9pbnRlcmFjdGl2ZXNoZWxsLnB5IikKCiAgICBlbGlmIElQeXRob24uX192ZXJzaW9uX18gPT0gIjguNC4wIjoKICAgICAgICAjIGxhYiBjb21wdXRlcnMKICAgICAgICBkZWYgZ2V0X2FzdChmcmFtZSk6CiAgICAgICAgICAgIHJldHVybiBhc3QuTW9kdWxlKGZyYW1lLmZfYmFjay5mX2JhY2suZl9sb2NhbHNbIm5vZGVsaXN0Il0pCiAgICAgICAgZGVmIGZpbmRfbG9jYWxzKGZyYW1lKToKICAgICAgICAgICAgcmV0dXJuIGZyYW1lLmZfbG9jYWxzCiAgICAgICAgZGVmIGF0X3RvcF9sZXZlbChmcmFtZSk6CiAgICAgICAgICAgIHJldHVybiBmcmFtZS5mX2JhY2suZl9jb2RlLmNvX2ZpbGVuYW1lLmVuZHN3aXRoKCJJUHl0aG9uL2NvcmUvaW50ZXJhY3RpdmVzaGVsbC5weSIpCiAgICBlbHNlOgogICAgICAgIHByaW50KGYicHJpbnRfbG9jYWxzKCkgbm90IHN1cHBvcnRlZCBvbiBJUHl0aG9uIHZlcnNpb24ge0lQeXRob24uX192ZXJzaW9uX199IikKCiAgICBkZWYgZ2V0X2NlbGxfbmFtZXMoZnJhbWUpOgogICAgICAgIHRyZWUgPSBnZXRfYXN0KGZyYW1lKQogICAgICAgIHZpc2l0b3IgPSBWaXNpdG9yKCkKICAgICAgICB2aXNpdG9yLnZpc2l0KHRyZWUpCiAgICAgICAgcmV0dXJuIGZpbHRlcl92YXJpYWJsZXModmlzaXRvci52YXJpYWJsZXMsIGZyYW1lLmZfbG9jYWxzKQoKICAgIGRlZiBmaW5kX3doaWNoKGZyYW1lKToKICAgICAgICAjIEZyYW1lIGlzIHRoZSBmcmFtZSB3aG9zZSBsb2NhbHMgd2UgYXJlIGludGVyZXN0ZWQgaW4gcHJpbnRpbmcuCiAgICAgICAgaWYgYXRfdG9wX2xldmVsKGZyYW1lKToKICAgICAgICAgICAgIyBUaGUgcGFyZW50IGZyYW1lIG9mIHRoZSBpbnRlcmVzdGVkIGZyYW1lIGlzIGEgbW9kdWxlLCBtb3N0IGxpa2VseQogICAgICAgICAgICAjICJpbnRlcmFjdGl2ZXNoZWxsIi4gVGhpcyBtZWFucyB3ZSBhcmUgaW4gdGhlIGdsb2JhbCBzY29wZSwgc2luY2UKICAgICAgICAgICAgIyBvbmx5IHRoZSBnbG9iYWwgc2NvcGUgc2hvdWxkIGJlIGRpcmVjdGx5IHJ1biBieSB0aGUgaW50ZXJhY3RpdmUgc2hlbGwuCiAgICAgICAgICAgIHJldHVybiBzZXQoZ2V0X2NlbGxfbmFtZXMoZnJhbWUpKQogICAgICAgICMgVGhlIHBhcmVudCBmcmFtZSBpcyBub3QgYSBtb2R1bGUsIHNvIHdlIGFyZSBpbiBhIGxvY2FsIHNjb3BlLgogICAgICAgIHJldHVybiBzZXQoZnJhbWUuZl9sb2NhbHMpCgogICAgZGVmIHByaW50X2xvY2Fscygqd2hpY2gsIHR5cGVzPUZhbHNlKToKICAgICAgICAiIiJQcmludCB0aGUgbG9jYWwgdmFyaWFibGVzIGluIHRoZSBjYWxsZXIncyBmcmFtZS4iIiIKICAgICAgICBpbXBvcnQgaW5zcGVjdAogICAgICAgICMgY3VycmVudGZyYW1lKCkgZnJhbWUgaXMgcHJpbnRfbG9jYWxzLiBXZSB3YW50IHRoZSBjYWxsZXIncyBmcmFtZQogICAgICAgIGZyYW1lID0gaW5zcGVjdC5jdXJyZW50ZnJhbWUoKS5mX2JhY2sKICAgICAgICBsb2NhbHMgPSBmaW5kX2xvY2FscyhmcmFtZSkKICAgICAgICB3aGljaCA9IHNldCh3aGljaCkgaWYgd2hpY2ggZWxzZSBmaW5kX3doaWNoKGZyYW1lKQogICAgICAgIGxsID0ge2s6IHYgZm9yIGssIHYgaW4gbG9jYWxzLml0ZW1zKCkgaWYgayBpbiB3aGljaH0KICAgICAgICBpZiBub3QgbGw6CiAgICAgICAgICAgIHByaW50KCJwcmludF9sb2NhbHM6IG5vIGxvY2FscyIpCiAgICAgICAgICAgIHJldHVybgogICAgICAgIGlmIHR5cGVzOgogICAgICAgICAgICBwcmludCgiXG4iLmpvaW4oZiJ7a306IHt0eXBlKHYpLl9fbmFtZV9ffSDihpAge3Z9IiBmb3IgaywgdiBpbiBsbC5pdGVtcygpKSkKICAgICAgICBlbHNlOgogICAgICAgICAgICBwcmludCgiOyAiLmpvaW4oZiJ7a30g4oaQIHtyZXByKHYpfSIgZm9yIGssIHYgaW4gbGwuaXRlbXMoKSkpCgogICAgcmV0dXJuIHByaW50X2xvY2FscwoKcHJpbnRfbG9jYWxzID0gbWFrZV9wcmludF9sb2NhbHMoKQ=="
exec(base64.b64decode(code), globals, locals)
f(globals(), locals())
del f
# Run this function
def check(fn, *input, expected):
result = fn(*input)
if expected != result:
print(
f"Function should return the value {expected}, it is returning the value {result}.")
else:
print(f"Congratulations, the test case passed!")
print_locals()
¶Hi friends! It's me, Orr. I wanted to tell you about a nice function us TAs made for you, called print_locals()
. This section is not so much a question as it is an example of how you can use this function to have a closer look at what's going on in your code.
When called, print_locals()
will print the value of each variable in its scope. Here's a simple example:
a = 1
b = a + 1
print_locals()
Here's another example, this time in loop function
L = [1, 2, 3, 4, 5, 6, 7]
product = 1
for i in L:
product *= i
print_locals()
print(f"Product is: {product}")
print_locals()
works in functions, too!
def isqrt(x):
if x == 0:
return 0
if x == 1:
return 1
for i in range(x + 1):
i_squared = i * i
print_locals()
if i_squared > x:
return i - 1
print(f'The integer square root of 18 is {isqrt(18)}')
Sometimes we have too many variables in our scope, or some of the variables are simply not interesting. You can tell print_locals
to only print some of the variables by passing their names as strings to the functions.
annoying_list = ["blah"] * 1000
x = 42
y = "Very interesting text!"
z = "Even more interesting text"
print_locals() # Ugh, prints x but also annoying_list
print_locals('x') # Only prints x :)
print_locals('x', 'y') # Prints both x and y :)
print_locals('x', 'y', 'z') # It works for any number of variables!
print_locals(x) # Doesn't work! Because we passed the *value* of x, rather than its name (as a string)
So, last week there were some important concepts you needed to understand which will help you in the coming weeks. To make sure you've got it, we've prepared a few exercises to help you 😀.
When we say functions are general it means that every function you define should be able to work for any valid input you give it.
It's just like how the len
function can give you the length of any list or any string.
len([9,3,2]) # 3
len("I'm excited for week 2!") # 23
len(9) # invalid input, TypeError
Imagine how much harder labs would have been last week if len
only worked for "hello world" 😖.
To reinforce this concept let's do an example problem :)
Anakai needs a function that can tell her the national dish of any Caribbean country. She writes the following code:
COUNTRIES = [
["Anguilla", "Pigeon peas with rice"],
["Antigua and Barbuda", "Fungee and Pepperpot"],
["Aruba", "Keshi Yena"],
["Bahamas", "Crack Conch with Peas and Rice"],
["Barbados", "Flying Fish and Cou Cou"],
["Bonaire", "Stroba Kabritu"],
["British Virgin Islands", "Fish & fungi"],
["Cayman Islands", "Turtle Stew"],
["Cuba", "Ropa Vieja"],
["Curaçao", "Keshi Yena"],
["Dominica", "Callaloo Soup"],
["Dominican Republic", "La bandera"],
["French Guiana", "Bouillon D'awara"],
["Grenada", "Oil Down"],
["Guadeloupe","Colombo"],
["Haiti", "Griot"],
["Jamaica", "Ackee and Saltfish"],
["Martinique", "Colombo"],
["Montserrat", "Goat Water"],
["Puerto Rico", "Arroz con Gandules"],
["Saint Kitts and Nevis", "Saltfish, dumplings & provisions"],
["Saint Lucia", "Saltfish"],
["Saint Martin", "Conchs and dumplings"],
["Sint Maarten", "Conchs and Dumplings"],
["Saint Vincent and the Grenadines","Roasted Breadfruit and Jackfish"],
["Trinidad and Tobago", "Crab & Callaloo"],
["Turks and Caicos Islands", "Peas, rice & fish"],
["US Virgin Islands", "Callaloo"]
]
def find_national_dish(country):
"""Takes the name of a Caribbean country and returns its national dish.
Input: country (str)
Output: (str)
"""
for country_list in COUNTRIES:
if country_list[0] == country:
return country_list[1]
return f"The national dish of {country} was not found :("
Using find_national_dish
, print the following national dishes
# Write your answers here
# 1.
# 2.
# 3.
# 4.
So, last week, understanding indentation in Python was very helpful for dealing with loops (for and while) and if statements. The indentation of the lines of code can determine whether it is part of a function or if its part of a loop or not. It can also determine when the line is run.
Just as a reminder, this was the definition for find_national_dish
def find_national_dish(country):
"""Takes the name of a Caribbean country and returns its national dish.
Input: country (str)
Output: (str)
"""
for country_list in COUNTRIES:
if country_list[0] == country:
return country_list[1]
return f"The national dish of {country} was not found :("
Anakai was messing around with the implementation and indented the last line to be in line with the if statement like:
def find_national_dish(country):
"""Takes the name of a Caribbean country and returns its national dish.
Input: country (str)
Output: (str)
"""
for country_list in COUNTRIES:
if country_list[0] == country:
return country_list[1]
return f"The national dish of {country} was not found :("
What would happen if she tests it by calling find_national_dish("Cuba")?
# Write your answer for 2.1 here in a comment
Last week we also learnt about scope in Python :). Each function has a scope (local scope) that is specific them. On the other hand, outside functions exists the global scope. Variables declared inside a function exist only inside that function's scope and cannot be used outside of it.
We also learnt about the global
keyword which can be used inside functions to tell Python to modify a variable in the global scope
rather than create a new variable in the function's scope.
Anakai also wants to make a program that can greet other persons. Once it gets the name of the person it should say hi and ask for their age. She tries to write the following code but it keeps failing 😞.
age = 0
def greet(name):
"""Prints a greeting
Input: name (str)
Output: (None)
"""
print(f"Hi, {name}")
def ask_age():
"""Asks a person what their age is
Input: (None)
Output: (None)
"""
age = int(input(f"{name}, how old are you?: "))
greet("Elijah")
ask_age()
print(f"Okay, now I know you're {age} years old")
What do you think would happen when the last three lines of this code are run? Explain why.
# Write your answer to 3.1 in a comment
Fix the code so that it works as intended
# Write your answer to 3.2 here
Dr. Mansingh is assigning grades to her students. Help her write a grading function that takes a student's score (out of 100) as input and returns a letter grade. The cutoffs for grades are included below.
Range | Grade |
---|---|
[90-100] | A+ |
[80-89] | A |
[70-79] | B |
[60-69] | C |
[50-59] | D |
[0-49] | F |
Define a helper function named isValidScore
that takes in a score as input and returns a boolean. If the score that is passed into this function is between 0
and 100
(both inclusive) return True otherwise return False.
def isValidScore(score):
"""Returns True if score is valid, False otherwise.
Input: score (int).
Output: (Boolean)
"""
# Put your code below this comment
return False
# TEST_CASE
# Note: if an error is given saying "check" is not defined, rerun the first code
# cell in this notebook.
check(isValidScore, 50, expected=True)
check(isValidScore, 101, expected=False)
check(isValidScore, -101, expected=False)
check(isValidScore, 100, expected=True)
check(isValidScore, 0, expected=True)
Define a function named grader
that has one argument, score
. Within the function you should call the isValidScore
function you defined in 2.1 by passing in the score. If the call to isValidScore
return True your function must return the string Valid Score
. Otherwise it should return the string Invalid Score
.
def grader(score):
""" Returns "Valid Score" if score is valid, otherwise "Invalid Score".
Input: score (int).
Output: "Valid Score" or "Invalid Score" (str).
"""
# Put your code below this comment
return ''
# Note: if an error is given saying "check" is not defined, rerun the first code
# cell in this notebook.
check(grader, 50, expected='Valid Score')
check(grader, 150, expected='Invalid Score')
check(grader, -10, expected='Invalid Score')
Modify the grader
function you defined in 2.2 so that it returns the letter grade for the score. Use the grade cutoffs written above. If the score is greater than or equal to 90 your function should return an A+, if the score is greater than or equal to 80 your function should return an A and so on. You should still use the isValidFunction
to check for invalid input and it must return the string Invalid Score
for any invalid scores.
def grader(score):
"""Returns the letter grade corresponding if score is valid, else "Invalid Score".
Input: score (int).
Output: (str)
"""
# Put your code below this comment
return ''
# TEST_CASE
# Note: if an error is given saying "check" is not defined, rerun the first code
# cell in this notebook.
check(grader, 90, expected='A+')
check(grader, 56, expected='D')
check(grader, 70, expected='B')
check(grader, -50, expected='Invalid Score')
check(grader, 105, expected='Invalid Score')
check(grader, -10, expected='Invalid Score')
Dr. Mansingh would like to know how many of her students have passed the exam. Here at UWI, 50 is the cutoff for passing, meaning that students pass if they get a score of at least 50 (out of 100).
Define a function named countHowManyPassedUWI
that takes in a list containing scores, and returns the number of scores in the list that are at least UWI's cutoff (50).
def countHowManyPassedUWI(score_list):
"""Returns how many scores in score_list are >= 50.
Input: score_list (list of ints).
Output: (int)
"""
# Put your code below this comment
return 0
Great job! Dr. Mansingh told Dr. Barak about your excellent work, and Dr. Barak asked to use your function for calculating passing grades at Harvard. However, at Harvard the cutoff is different in each department. For example, in the Dept. of Computer Science the cutoff is 50 (like at UWI), but at the Dept. of Linguistics the cutoff is 55.
Dr. Barak would like you to define a single function that works for any department at Harvard. Define a function named countHowManyPassed
that takes in a list containing scores as a first argument and the cutoff for passing scores as a second argument. The function should then return the count of the number of scores in the list that are above or equal to the passing score.
def countHowManyPassed(score_list, cutoff):
"""Returns how many scores in score_list are >= cutoff.
Input: score_list (list of ints), cutoff (int).
Output: (int)
"""
# Put your code below this comment
return 0
# TEST_CASE
# Note: if an error is given saying "check" is not defined, rerun the first code
# cell in this notebook.
check(countHowManyPassed, [40, 99, 50, 80, 78,
30, 49, 48, 100, 51], 50, expected=6)
check(countHowManyPassed, [320, 100, 243, 134, 677,
200, 531, 544, 200, 120], 200, expected=7)
Next, Dr. Barak would like to know that percentage of passing students. You can calculate the percentage of students who passed using the formula: (number_of_passing_students / number_of_students) * 100
.
Calculate the percentage of students that passed the exam in last year's Advanced Topics in Computer Science class. There were a total of eight students, who's scores are specified below.
score_list = [40, 99, 50, 80, 78, 30, 49, 48]
number_of_students = len(score_list)
cutoff = 50
number_of_passing_students = countHowManyPassed(score_list, cutoff)
# Write your code below this comment
Define a function named calculatePercentage
that accepts two arguments. The first argument is a list of students' scores, and the second argument is the cutoff for passing score. It returns the percentage of the students that passed.
Your function should call the countHowManyPassed
function you defined earlier.
def calculatePercentage(score_list, cutoff):
"""Returns percentage of scores in score_list that are >= cutoff.
Input: score_list (list of ints), cutoff (int).
Output: (int)
"""
# Put your code below this comment
return 0
# TEST_CASE
# Note: if an error is given saying "check" is not defined, rerun the first code
# cell in this notebook.
check(calculatePercentage, [320, 333, 243, 134, 677,
644, 531, 544, 450, 120], 325, expected=60.0)
check(calculatePercentage, [320, 100, 243, 134, 677,
200, 531, 544, 200, 120], 200, expected=70.0)
Orr keeps talking about something called Armstrong numbers, which he thinks are "really cool" 🤷. A three digit integer is an Armstrong number if the sum of the cubes of its digits is equal to the number itself. For example, 371 is an Armstrong number since 33 + 73 + 13 = 371.
Orr asks you to find all Armstrong numbers.
Define a helper function named extractDigits
that is going to take in an integer and returns the individual digits within the integer as a list. For example, if you give it 371 it should return the list [1, 3, 7]
. Your list must be sorted in ascending order. Hint: You can use the following pseudo-code:
n
.digits = create an empty list
n > 0
:n
, by settings current_digit = n % 10
.current_digit
to digits
.n
by 10
(ignoring the remainder), and repeat.digits
.def extractDigits(n):
""" Returns a list of all digits in the number n.
Input: n (int).
Output: (list of ints).
"""
return []
# TEST_CASE
# Note: if an error is given saying "check" is not defined, rerun the first code
# cell in this notebook.
ed_set = lambda n : set(extractDigits(n))
check(ed_set, 371, expected=set([1, 3, 7]))
check(extred_setactDigits, 985, expected=set([5, 8, 9]))
check(ed_set, 652, expected=set([2, 5, 6]))
Define a helper function named sumDigits
that takes a list of digits and then cubes each digit and sums up the cubes.
For example, sumDigits([2, 0, 1])
it should return 23 + 03 + 13 = 9. As another example, sumDigits([3, 7, 1])
should return 33 + 73 + 13 = 371.
def sumDigits(list_of_digits):
""" Returns the sum of cubes of the digits in list_of_digits.
Input: list_of_digits (list of ints).
Output: (int).
"""
# Put your code below this comment
return 0
# TEST_CASE
# Note: if an error is given saying "check" is not defined, rerun the first code
# cell in this notebook.
check(sumDigits, [3, 7, 1], expected=371)
check(sumDigits, [4, 2, 3], expected=99)
Define a helper function named isArmstrong
that takes a number and returns True
if the number is an Armstrong number, otherwise returns False.
You should use the extractDigits
and sumDigits
functions you defined earlier. Here's an idea: Given a number n
,
extractDigits(n)
and store the result in a variable digits
.sumDigits(digits)
and store the result in a variable k
.k == n
, then n
is an Armstrong so you should return True
. Otherwise, return False
.def isArmstrong(n):
"""Returns True if n is an Armstrong number, else False.
Input: n (int).
Output: (Boolean).
"""
# Put your code below this comment
return False
# TEST_CASE
# Note: if an error is given saying "check" is not defined, rerun the first code
# cell in this notebook.
check(isArmstrong, 371, expected=True)
check(isArmstrong, 372, expected=False)
check(isArmstrong, 153, expected=True)
check(isArmstrong, 407, expected=True)
check(isArmstrong, 370, expected=True)
Define a function named findArmstrongNumbers
that finds all 3 digit armstrong numbers. It should return a list of all three digit Armstrong numbers.
Hint: Initialize a list armstrongs = []
. Then, for each number between 100
and 999
, check if the number is an Armstrong number (using isArmstrong
). If it is, add it to armstrongs
.
def findArmstrongNumbers():
"""Returns a list of all three-digit Armstrong numbers.
Input: (None).
Output: (list of ints).
"""
# Put your code below this comment
return []
# TEST_CASE
# Note: if an error is given saying "check" is not defined, rerun the first code
# cell in this notebook.
check(findArmstrongNumbers, expected=4)