Functions
Parameters
Instructions
The function mult_two_add_three() prints a number multiplied by 2 and
added to 3.
Pass the number 1 into your function call.
Call the function with the value 5, -1, 0 as the argument.
def mult_two_add_three(number):
print(number * 2 + 3)
mult_two_add_three(1)
mult_two_add_three(5)
mult_two_add_three(-1)
mult_two_add_three(0)
Multiple Parameters
Instructions
The function mult_two_add_three takes a number, multiplies it by two and
adds three. We want to make this more flexible.
First, change the name of the function to mult_x_add_y.
Now, add x and y as parameters of the function, after number.
Inside the function, replace 2 in the print statement with x, and replace 3 in
the print statement with y.
Call the function with these values:
number: 5
x: 2
y: 3
Call the function with these values:
number: 1
x: 3
y: 1
def mult_x_add_y(number,x, y):
print(number * x + y)
mult_x_add_y(5, 2, 3)
mult_x_add_y(1, 3, 1)
Keyword Arguments
Instructions
We have defined a function create_spreadsheet, which takes in a title, and
prints that it is creating a spreadsheet.
Add the parameter row_count to the function definition. Set the default
value to be 1000.
Change the print statement in the function to print “Creating a spreadsheet
called title with row_count rows”, where title and row_count are replaced
with their respective values.
Call create_spreadsheet() with title set to "Applications" and row_count set
to 10.
def create_spreadsheet(title, row_count = 1000):
print("Creating a spreadsheet called " + title + " with " +
str(row_count) + " rows")
create_spreadsheet("Downloads")
create_spreadsheet("Applications", 10)
Returns
Instructions
The function calculate_age creates a variable called age that is the
difference between the current year, and a birth year. Add a line to
return age.
Outside of the function, call calculate_age with values 2049, 1993 and save
the value to a variable called my_age.
Call calculate_age with values 2049, and 1953 and save the value to a
variable called dads_age.
Print the string "I am X years old and my dad is Y years old" to the console,
with my_age where the X is and dads_age where the Y is.
def calculate_age(current_year, birth_year):
age = current_year - birth_year
return age
my_age = calculate_age(2049, 1993)
dads_age = calculate_age(2049, 1953)
print(" I am " +str(my_age) + " years old and my dad is " +
str(dads_age) + " years old")
Multiple Return Values
Instructions
Write a function called get_boundaries() that takes in two parameters, a
number called target and a number called margin.
It should create two variables:
low_limit: target minus the margin
high_limit: margin added to target
Return both low_limit and high_limit from the function, in that order.
Call the function on the target 100 with a margin of 20. Save the returned
values to variables called low and high.
def get_boundaries(target, margin):
low_limit = target - margin
high_limit = margin + target
return low_limit, high_limit
low, high = get_boundaries(100, 20)
Scope
Instructions
Outside of the function calculate_age(), try to print current_year. Does it
work?
Remove both print statements.
Let’s try something different. Remove the parameter current_year so that it
is no longer a parameter of calculate_age().
It’s the year 2048.
Define current_year as a variable BEFORE defining the function and give it
the value 2048. Now, every time calculate_age() is called, it should only
take birth_year.
Try to print current_year one last time. Does it work finally?
Hooray! Now we have current_year globally defined. Great work!
Let’s make sure our function still works: print the value
of calculate_age() with 1970 as the argument.
current_year = 2048
def calculate_age(birth_year):
age = current_year - birth_year
return age
print(current_year)
print(calculate_age(1970))
Review
Define a function called repeat_stuff that takes in two inputs, stuff,
and num_repeats.
We will want to make this function print a string
with stuff repeated num_repeats amount of times.
Outside of the function, call repeat_stuff.
You can use the value "Row " for stuff and 3 for num_repeats.
Add repeat_stuff("Row ", 3) and the string "Your Boat. " together and
save the result to a variable called lyrics.
Create a variable called song and assign it the value
of repeat_stuff called with the singular input lyrics.
Print song.
def repeat_stuff(stuff, num_repeats=10):
return stuff*num_repeats
lyrics = repeat_stuff("Row ", 3) + "Your Boat. "
song = repeat_stuff(lyrics)
print(song)
Getting Ready for Physics Class
Write a function called f_to_c that takes an input f_temp, a temperature in
Fahrenheit, and converts it to c_temp, that temperature in Celsius.
It should then return c_temp.
The equation you should use is:
Temp (C) = (Temp (F) - 32) * 5/9
Let’s test your function with a value of 100 Fahrenheit.
Define a variable f100_in_celsius and set it equal to the value
of f_to_c with 100 as an input.
Write a function called c_to_f that takes an input c_temp, a temperature in
Celsius, and converts it to f_temp, that temperature in Fahrenheit.
It should then return f_temp.
The equation you should use is:
Temp (F) = Temp (C) * (9/5) + 32
Let’s test your function with a value of 0 Celsius.
Define a variable c0_in_fahrenheit and set it equal to the value
of c_to_f with 0 as an input.
Use the Force
Define a function called get_force that takes in mass and acceleration. It
should return mass multiplied by acceleration.
Test get_force by calling it with the
variables train_mass and train_acceleration.
Save the result to a variable called train_force and print it out.
Print the string “The GE train supplies X Newtons of force.”, with X replaced
by train_force.
Define a function called get_energy that takes in mass and c.
c is a constant that is usually set to the speed of light, which is roughly 3 x
10^8. Set c to have a default value of 3*10**8.
get_energy should return mass multiplied by c squared.
Test get_energy by using it on bomb_mass, with the default value of c. Save
the result to a variable called bomb_energy.
Print the string “A 1kg bomb supplies X Joules.”, with X replaced
by bomb_energy.
Do the Work
Define a final function called get_work that takes in mass, acceleration,
and distance.
Work is defined as force multiplied by distance. First, get
the force using get_force, then multiply that by distance. Return the result.
Test get_work by using it on train_mass, train_acceleration,
and train_distance. Save the result to a variable called train_work.
Print the string "The GE train does X Joules of work over Y meters.",
with X replaced with train_work and Y replaced with train_distance.
train_mass = 22680
train_acceleration = 10
train_distance = 100
bomb_mass = 1
def f_to_c(f_temp):
c_temp = (f_temp - 32) * 5/9
return c_temp
f100_in_celsius = f_to_c(100)
def c_to_f(c_temp):
f_temp = c_temp * (9/5) + 32
return f_temp
c0_in_fahrenheit = c_to_f(0)
def get_force(mass, acceleration):
return mass * acceleration
train_force = get_force(train_mass, train_acceleration)
print("The GE train supplies " + str(train_force) + " Newtons of force.")
def get_energy(mass, c = 3*10**8):
return mass * c
bomb_energy = get_energy(bomb_mass)
print("A 1kg bomb supplieas " + str(bomb_energy) + " Joules.")
def get_work(mass, acceleration, distance):
force = get_force(mass, acceleration)
return force * distance
train_work = get_work(train_mass, train_acceleration, train_distance)
print("The GE train does " + str(train_work) + " Joules of work over " +
str(train_distance) + " meters.")
CODE CHALLENGE:
Average
average()
Instructions
Write a function named average() that has two parameters
named num1 and num2.
The function should return the average of these two numbers.
def average(num1, num2):
return (num1 + num2)/2
print(average(1, 100))
print(average(1, -1))
Tenth Power
tenth_power()
Instructions
Write a function named tenth_power() that has one parameter named num.
The function should return num raised to the 10th power.
def tenth_power(num):
return num**10
print(tenth_power(1))
print(tenth_power(0))
print(tenth_power(2))
Bond
introduction()
Instructions
Write a function named introduction() that has two parameters
named first_name and last_name.
The function should return the last_name, followed by a comma, a
space, first_name another space, and finally last_name.
def introduction(first_name, last_name):
return last_name + ", " + first_name + " " + last_name
print(introduction("James", "Bond"))
print(introduction("Maya", "Angelou"))
Square Root
square_root()
Instructions
Write a function named square_root() that has one parameter named num.
Use exponents (**) to return the square root of num.
def square_root(num):
return num**(1/2)
print(square_root(16))
print(square_root(100))
Tip
tip()
Instructions
Create a function called tip() that has two parameters
named total and percentage.
This function should return the amount you should tip given a total and the
percentage you want to tip
def tip(total, percentage):
return total * (percentage/100)
print(tip(10, 25))
print(tip(0, 100))
Win Percentage
win_percentage()
Instructions
Create a function called win_percentage() that takes two parameters
named wins and losses.
This function should return out the total percentage of games won by a
team based on these two numbers.
def win_percentage(wins, losses):
return wins/(wins + losses) * 100
print(win_percentage(5, 5))
print(win_percentage(10, 0))
First Three Multiples
first_three_multiples()
Instructions
Write a function named first_three_multiples() that has one parameter
named num.
This function should print the first three multiples of num. Then, it should
return the third multiple.
For example, first_three_multiples(7) should print 7, 14, and 21 on three
different lines, and return 21.
def first_three_multiples(num):
print(num)
print(num*2)
print(num*3)
return num*3
first_three_multiples(10)
first_three_multiples(0)
Dog Years
dog_years()
Instructions
Some say that every one year of a human’s life is equivalent to seven years
of a dog’s life. Write a function named dog_years() that has two parameters
named name and age.
The function should compute the age in dog years and return the following
string:
"{name}, you are {age} years old in dog years"
Test this function with your name and your age!
def dog_years(name, age):
return name+", you are "+str(age*7)+" years old in dog years"
print(dog_years("Lola", 16))
print(dog_years("Baby", 0))
Remainder
remainder()
Instructions
Write a function named remainder() that has two parameters
named num1 and num2.
The function should return the remainder of twice num1 divided by half
of num2.
def remainder(num1, num2):
return (2*num1) % (num2*0.5)
print(remainder(15, 14))
print(remainder(9, 6))
Lots of Math
lots_of_math()
Instructions
Create a function named lots_of_math(). This function should have four
parameters named a, b, c, and d. The function should print 3 lines and
return 1 value.
First, the sum of a and b.
Second, d subtracted from c.
Third, the first number printed, multiplied by the second number printed.
Finally, it should return the third number printed mod a.
def lots_of_math(a, b, c, d):
print(a + b)
print(d - c)
print((a + b) * (d - c))
return ((a + b) * (d - c))%a
print(lots_of_math(1, 2, 3, 4))
print(lots_of_math(1, 1, 1, 1))
Control Flow
Boolean Expressions
Instructions
Determine if the following statements are boolean expressions or not. If
they are, set the matching variable to the right to "Yes" and if not set the
variable to "No". Here’s an example of what to do:
Example statement:
My dog is the cutest dog in the world.
This is an opinion and not a boolean expression, so you would
set example_statement to "No" in the editor to the right. Okay, now it’s
your turn:
Statement one:
Dogs are mammals.
Statement two:
My dog is named Pavel.
Statement three:
Dogs make the best pets.
Statement four:
Cats are female dogs.
example_statement = "No"
statement_one = "Yes"
statement_two = "Yes"
statement_three = "No"
statement_four = "Yes"
Relational Operators
Instructions
Determine if the following boolean expressions are True or False. Input your
answer as True or False in the appropriate variable to the right.
Statement one:
(5 * 2) - 1 == 8 + 1
Statement two:
13 - 6 != (3 * 2) + 1
Statement three:
3 * (2 - 1) == 4 - 1
statement_one = True
statement_two = False
statement_three = True
Boolean Variables
Instructions
Create a variable named my_baby_bool and set it equal to "true".
Check the type of my_baby_bool using type(my_baby_bool).
You’ll have to print it to get the results to display in the terminal.
It’s not a boolean variable! Boolean values True and False always need to be
capitalized and do not have quotation marks.
Create a variable named my_baby_bool_two and set it equal to True.
Check the type of my_baby_bool_two and make sure you successfully
created a boolean variable.
You’ll have to print it to get the results to display in the terminal.
You can print the type of a variable by running: print(type(variable_name))
my_baby_bool = "true"
print(type(my_baby_bool))
my_baby_bool_two = True
print(type(my_baby_bool_two))
If Statements
Instructions
In the workspace [Link] there is a function with an if statement. I wrote
this function because my coworker Dave kept using my computer without
permission and he is a real doofus. It takes user_name as an input and if the
user is Dave it tells him to stay off my computer.
Enter a user name in the field for user_name and try running the function.
Ugh! Dave got around my security and has been logging onto my
computer using our coworker Angela’s user name, angela_catlady_87.
Update the function with a second if statement so it checks for this user
name as well and returns in response. That’ll teach him!
"I know it is you Dave! Go away!"
def dave_check(user_name):
if user_name == "Dave":
return "Get off my computer Dave!"
if user_name == "angela_catlady_87":
return "I know it is you Dave! Go away!"
user_name = "angela_catlady_87"
print(dave_check(user_name))
Relational Operators II
Greater than: >
Less than: <
Greater than or equal to: >=
Less than or equal to: <=
Instructions
[Link] a function called greater_than that takes two integer
inputs, x and y and returns the value that is greater. If x and y are equal,
return the string
"These numbers are the same"
def greater_than(x, y):
if x > y:
return x
if y > x:
return y
if x == y:
return "These numbers are the same"
Boolean Operators: and
Instructions
[Link] the variables statement_one and statement_two equal to the results
of the following boolean expressions:
Statement one:
(2 + 2 + 2 >= 6) and (-1 * -1 < 0)
Statement two:
(4 * 2 <= 8) and (7 - 1 == 6)
[Link]’s return to Calvin Coolidge’s Cool College. 120 credits aren’t the only
graduation requirement, you also need to have a GPA of 2.0 or higher.
Rewrite the graduation_reqs function so it takes two
inputs, gpa and credits, and checks to see if a student meets both
requirements using an and statement.
If they do, return the string
"You meet the requirements to graduate!"
statement_one = (2 + 2 + 2 >= 6) and (-1 * -1 < 0)
statement_two = (4 * 2 <= 8) and (7 - 1 == 6)
def graduation_reqs(gpa, credits):
if gpa >= 2.0 and credits >= 120:
return "You meet the requirements to graduate!"
Boolean Operators: or
Instructions
[Link] the variables statement_one and statement_two equal to the results
of the following boolean expressions:
Statement one:
(2 - 1 > 3) or (-5 * 2 == -10)
Statement two:
(9 + 5 <= 15) or (7 != 4 + 3)
[Link] registrars office at Calvin Coolidge’s Cool College has another request.
They want to send out a mailer with information on the commencement
ceremonies to students who have met at least one requirement for
graduation (120 credits and 2.0 GPA).
Write a function called graduation_mailer that takes two
inputs, gpa and credits and checks if a student either has 120 or more
credits or a GPA 2.0 or higher and if so returns True.
statement_one = (2 - 1 > 3) or (-5 * 2 == -10)
statement_two = (9 + 5 <= 15) or (7 != 4 + 3)
def graduation_mailer(gpa, credits):
if gpa >= 2.0 or credits >= 120:
return True
Boolean Operators: not
Instructions
[Link] the variables statement_one and statement_two equal to the results
of the following boolean expressions:
Statement one:
not (4 + 5 <= 9)
Statement two:
not (8 * 2) != 20 - 4
[Link] registrar’s office at Calvin Coolidge’s Cool College has been so
impressed with your work so far that they have another task for you. They
want you to return to the first function you wrote, graduation_reqs, and add
in several checks using and and not statements.
If a student meets both requirements the function should
return
"You meet the requirements to graduate!"
If a student’s GPA is greater or equal to 2.0 but they don’t have
enough credits the function should return
"You do not have enough credits to graduate."
If they have enough credits but their GPA is less than 2.0 the
function should return
"Your GPA is not high enough to graduate."
If they do not have enough credits and their GPA is less than
2.0, the function should return
"You do not meet either requirement to graduate!"
Make sure your return value matches those strings exactly. Capitalization,
punctuation, and spaces matter!
statement_one = not (4 + 5 <= 9)
statement_two = not (8 * 2) != 20 - 4
def graduation_reqs(gpa, credits):
if (gpa >= 2.0) and (credits >= 120):
return "You meet the requirements to graduate!"
if gpa >= 2.0:
return "You do not have enough credits to graduate."
if credits >= 120:
return "Your GPA is not high enough to graduate."
else:
return "You do not meet either requirement to graduate!"
Else Statements
Instructions
[Link] Coolidge’s Cool College has another request for you. If a student is
failing to meet both graduation requirements, they want the function to
return:
"You do not meet the GPA or the credit requirement for graduation."
Use an else statement to add this to your function.
def graduation_reqs(gpa, credits):
if (gpa >= 2.0) and (credits >= 120):
return "You meet the requirements to graduate!"
if (gpa >= 2.0) and not (credits >= 120):
return "You do not have enough credits to graduate."
if not (gpa >= 2.0) and (credits >= 120):
return "Your GPA is not high enough to graduate."
else:
return "You do not meet the GPA or the credit requirement for
graduation."
Else If Statements
Instructions
[Link] Coolidge’s Cool College has noticed that students prefer to get
letter grades over GPA numbers. They want you to write a function
called grade_converter that converts an inputted GPA into the appropriate
letter grade. Your function should be named grade_converter, take the
input gpa, and convert the following GPAs:
4.0 or higher should return "A"
3.0 or higher should return "B"
2.0 or higher should return "C"
1.0 or higher should return "D"
0.0 or higher should return "F"
You can do this by creating a variable called grade.
Then, you should use elif statements to set grade to the appropriate letter
grade for the gpa entered.
At the end of the function, return grade.
def grade_converter(gpa):
grade = "F"
if gpa >= 4.0:
grade = "A"
elif gpa >= 3.0:
grade = "B"
elif gpa >= 2.0:
grade = "C"
elif gpa >= 1.0:
grade = "D"
return grade
Try and Except Statements
if, elif, and else statements aren’t the only way to build a control flow into
your program. You can use try and except statements to check for possible
errors that a user might encounter.
The general syntax of a try and except statement is
try:
# some statement
except ErrorName:
# some statement
First, the statement under try will be executed. If at some point an
exception is raised during this execution, such as a NameError or
a ValueError and that exception matches the keyword in
the except statement, then the try statement will terminate and
the except statement will execute.
Let’s take a look at this in an application. I want to write a function that
takes two numbers, a and b as an input and then returns a divided by b.
But, there is a possibility that b is zero, which will cause an error, so I want
to include a try and except flow to catch this error.
def divides(a,b):
try:
result = a / b
print (result)
except ZeroDivisionError:
print ("Can't divide by zero!")
Instructions
[Link] function in the editor is very simple and serves one purpose: it raises
a ValueError.
Try running it by entering raises_value_error() into the code editor and
hitting run.
Remember, unindent this function call so it isn’t included in the function
itself.
[Link]! Nice error raising! Now let’s make that error message a little more
palatable.
Write a try statement and an except statement around the line of code that
executes the function to catch a ValueError and make the error message
print You raised a ValueError!
def raises_value_error():
raise ValueError
try:
raises_value_error()
except ValueError:
print("You raised a ValueError!")
Review
Let’s put these skills to the test!
Instructions
[Link] admissions office at Calvin Coolidge’s Cool College collect three
pieces of information for each applicant:
1. Their high school GPA, on a 0.0 - 4.0 scale.
2. Their personal statement, which is given a score on a 1 - 100
scale.
3. The number of extracurricular activities they participate in.
They want students that have a GPA of 3.0 or higher, a personal statement
with a score of 90 or higher, and who participated in 3 or more
extracurricular activities.
Write a function called applicant_selector which takes three
inputs, gpa, ps_score, and ec_count. If the applicant meets the cutoff point
for all three categories, have the function return the string:
"This applicant should be accepted."
[Link]! The admissions office also wants to give students who have a high
GPA and a strong personal statement a chance even if they don’t
participate in enough extracurricular activities.
If an applicant meets the cutoff point for GPA and personal statement
score, but not the extracurricular activity count, the function should return
the string:
"This applicant should be given an in-person interview."
[Link], for all other cases, the function should return the string:
"This applicant should be rejected."
def applicant_selector(gpa, ps_score, ec_count):
if gpa >= 3.0 and ps_score >= 90 and ec_count >= 3:
return "This applicant should be accepted."
elif gpa >= 3.0 and ps_score >= 90 and ec_count < 3:
return "This applicant should be given an in-person interview."
else:
return "This applicant should be rejected."
Sal's Shipping
Sal runs the biggest shipping company in the tri-county area, Sal’s Shippers.
Sal wants to make sure that every single one of his customers has the best,
and most affordable experience shipping their packages. In this project,
you’ll build a program that will take the weight of a package and determine
the cheapest way to ship that package using Sal’s Shippers.
Sal’s Shippers has several different options for a customer to ship their
package. They have ground shipping, which is a small flat charge plus a rate
based on the weight of your package. Premium ground shipping, which is a
much higher flat charge, but you aren’t charged for weight. They recently
also implemented drone shipping, which has no flat charge, but the rate
based on weight is triple the rate of ground shipping.
Ground Shipping
Weight of package price per pound flat charge
2 lb or less 1.50 20.00
Over 2, less 6lb 3.00 20.00
Over 6, less 10lb 4.00 20.00
Over 10lb 4.75 20.00
Drone Shipping
Weight of package price per pound flat charge
2 lb or less 4.50 00.00
Over 2, less 6lb 9.00 00.00
Over 6, less 10lb 12.00 00.00
Over 10lb 14.25 00.00
Premium Ground Shipping
Flat charge: $125.00
Write a program that asks the user for the weight of their package and then
tells them which method of shipping is cheapest and how much it will cost
to ship their package using Sal’s Shippers.
Finding the Cheapest Shipping Method
[Link] off, we need to know how much it costs to ship a package of given
weight by normal ground shipping.
Write a function for the cost of ground shipping. This function should take
one parameter, weight, and return the cost of shipping a package of that
weight.
2.A package that weighs 8.4 pounds should cost $53.60 to ship with normal
ground shipping:
8.4\ lb \times \$4.00 + \$20.00 = \$53.608.4 lb×$4.00+$20.00=$53.60
Test that your ground shipping function gets the same value.
[Link]’ll also need to make sure we include the price of premium ground
shipping in our code.
Create a variable for the cost of premium ground shipping.
Note: this does not need to be a function because the price of premium
ground shipping does not change with the weight of the package.
[Link] a function for the cost of drone shipping. This function should take
one parameter, weight, and return the cost of shipping a package of that
weight.
5.A package that weighs 1.5 pounds should cost $6.75 to ship by drone:
1.5\ lb \times \$4.50 + \$0.00 = \$6.751.5 lb×$4.50+$0.00=$6.75
Test that your drone shipping function gets the same value.
[Link] those two functions for ground shipping cost and drone shipping
cost, as well as the cost of premium ground shipping, write a function that
takes one parameter, weight and prints a statement that tells the user
The shipping method that is cheapest.
How much it would cost to ship a package of said weight using this
method.
[Link] job! Now, test your function!
What is the cheapest method of shipping a 4.8 pound package and how
much would it cost?
What is the cheapest method of shipping a 41.5 pound package and how
much would it cost?
def ground_shipping(weight):
if weight <= 2:
price = weight * 1.5
elif weight <= 6:
price = weight * 3.0
elif weight <= 10:
price = weight * 4.0
else:
price = weight * 4.75
return price + 20
premium_shipping = 125
def drone_shipping(weight):
if weight <= 2:
price = weight * 4.5
elif weight <= 6:
price = weight * 9.0
elif weight <= 10:
price = weight * 12.0
else:
price = weight * 14.25
return price
def cheapest_shipping(weight):
if (ground_shipping(weight) < drone_shipping(weight)) and
(ground_shipping(weight) < premium_shipping):
print(“Ground shipping is the cheapest!”)
return ground_shipping(weight)
elif (drone_shipping(weight) < ground_shipping(weight)) and
(drone_shipping(weight) < premium_shipping):
print(“Drone shipping is the cheapest!”)
return drone_shipping(weight)
else:
print(“Premium shipping is the cheapest!”)
return premium_shipping
print(cheapest_shipping(4.8))
print(cheapest_shipping(41.5))
CODE CHALLENGE: CONTROL FLOW
In Range
in_range(num, lower, upper)
Instructions
[Link] a function named in_range() that has three parameters
named num, lower, and upper.
The function should return True if num is greater than or equal
to lower and less than or equal to upper. Otherwise, return False.
def in_range(num, lower, upper):
if(num >= lower and num <= upper):
return True
return False
print(in_range(10, 10, 10))
print(in_range(5, 10, 20))
Movie Review
movie_review(rating)
Instructions
[Link] a function named movie_review() that has one parameter
named rating.
If rating is less than or equal to 5, return "Avoid at all costs!". If rating is
between 5 and 9, return "This one was fun.". If rating is 9 or above,
return "Outstanding!"
def movie_review(rating):
if rating <= 5:
return "Avoid at all costs!"
elif rating > 5 and rating < 9:
return "This one was fun."
else:
return "Outstanding!"
print(movie_review(9))
print(movie_review(4))
print(movie_review(6))
Twice as Large
twice_as_large(num1, num2)
Instructions
[Link] a function named twice_as_large() that has two parameters
named num1 and num2.
Return True if num1 is more than double num2. Return False otherwise.
def twice_as_large(num1, num2):
if num1 > 2 * num2:
return True
return False
print(twice_as_large(10, 5))
print(twice_as_large(11, 5))
Power
large_power(base, exponent)
Instructions
[Link] a function named large_power() that takes two parameters
named base and exponent.
If base raised to the exponent is greater than 5000, return True, otherwise
return False
def large_power(base, exponent):
if base**exponent > 5000:
return True
return False
print(large_power(2, 13))
print(large_power(2, 12))
Divisible By Ten
divisible_by_ten(num)
Instructions
[Link] a function called divisible_by_ten() that has one parameter
named num.
The function should return True if num is divisible by 10,
and False otherwise. Consider how to use modulo (%) to check for
divisibility.
def divisible_by_ten(num):
if num % 10 == 0:
return True
return False
print(divisible_by_ten(20))
print(divisible_by_ten(25))
Max Number
max_num(num1, num2, num3)
Instructions
[Link] a function called max_num() that has three parameters
named num1, num2, and num3.
The function should return the largest of these three numbers. If any of two
numbers tie as the largest, you should return "It's a tie!".
def max_num(num1, num2, num3):
if num1 > num2 and num1 > num3:
return num1
elif num2 > num1 and num2 > num3:
return num2
elif num3 > num1 and num3 > num2:
return num3
else:
return "It's a tie!"
print(max_num(-10, 0, 10))
print(max_num(-10, 5, -30))
print(max_num(-5, -10, -10))
print(max_num(2, 3, 3))
Over Budget
over_budget(budget, food_bill, electricity_bill, internet_bill, rent)
Instructions
[Link] a function called over_budget that has five parameters
named budget, food_bill, electricity_bill, internet_bill, and rent.
The function should return True if budget is less than the sum of the other
four parameters. You’ve gone over budget! Return False otherwise.
def over_budget(budget, food_bill, electricity_bill, internet_bill, rent):
if budget < food_bill + electricity_bill + internet_bill + rent:
return True
return False
print(over_budget(100, 20, 30, 10, 40))
print(over_budget(80, 20, 30, 10, 30))
Always False
always_false(num)
Instructions
[Link] a function named always_false() that has one parameter
named num.
Using an if statement, your variable num, and the operators >, and <, make
it so your function will return False no matter what number is stored
in num.
An if statement that is always false is called a contradiction. You will rarely
want to do this while programming, but it is important to realize it is
possible to do this.
def always_false(num):
if num >= 0 and num < 0:
return True
return False
print(always_false(0))
print(always_false(-1))
print(always_false(1))
Not Equal
not_sum_to_ten(num1, num2)
Instructions
[Link] a function named not_sum_to_ten() that has two parameters
named num1 and num2.
Return True if num1 and num2 do not sum to 10. Return False otherwise.
def not_sum_to_ten(num1, num2):
if num1 + num2 != 10:
return True
return False
print(not_sum_to_ten(9, -1))
print(not_sum_to_ten(9, 1))
print(not_sum_to_ten(5,5))
Same Name
same_name(your_name, my_name)
Instructions
[Link] a function named same_name() that has two parameters
named your_name and my_name.
If our names are identical, return True. Otherwise, return False.
def same_name(your_name, my_name):
if your_name == my_name:
return True
return False
print(same_name("Colby", "Colby"))
print(same_name("Tina", "Amber"))
LIST
What is a list?
A list is an ordered set of objects in Python.
Instructions
1.A new student named 'Vik' has joined our class. Vik is 68 inches tall. Add a
sublist to heights that represents Vik and his height.
heights = [['Jenny', 61], ['Alexus', 70], ['Sam', 67], ['Grace', 64]]
[Link] a list of lists called ages where each sublist contains a student’s
name and their age. Use the following data:
'Aaron' is 15
'Dhruti' is 16
heights = [['Jenny', 61], ['Alexus', 70], ['Sam', 67], ['Grace', 64], ['Vik',
68]]
ages = [['Aaron', 15], ['Dhruti', 16]]
Zip
names = ['Jenny', 'Alexus', 'Sam', 'Grace']
heights = [61, 70, 67, 65]
If we wanted to create a list of lists that paired each name with a height, we
could use the command zip. zip takes two (or more) lists as inputs and
returns an object that contains a list of pairs. Each pair contains one
element from each of the inputs. You won’t be able to see much about this
object from just printing it:
names_and_heights = zip(names, heights)
print(names_and_heights)
because it will return the location of this object in memory. Output
would look something like this:
<zip object at 0x7f1631e86b48>
To see the nested lists, you can convert the zip object to a list first:
print(list(names_and_heights))
returns:
[('Jenny', 61), ('Alexus', 70), ('Sam', 67), ('Grace', 65)]
Instructions
[Link] zip to create a new variable called names_and_dogs_names that
combines names and dogs_names into a zip object.
Make sure to run the code for this step before proceeding to the next
instruction!
.
[Link] a new variable named list_of_names_and_dogs_names by
calling list() on names_and_dogs_names. Print this new variable .
names = ['Jenny', 'Alexus', 'Sam', 'Grace']
dogs_names = ['Elphonse', 'Dr. Doggy DDS', 'Carter', 'Ralph']
names_and_dogs_names = zip(names, dogs_names)
list_of_names_and_dogs_names = list(names_and_dogs_names)
print(list_of_names_and_dogs_names)
Growing a List: Append
We can add a single element to a list using .append(). For example, suppose
we have an empty list called empty_list:
empty_list = []
We can add the element 1 using the following commands:
empty_list.append(1)
If we examine empty_list, we see that it now contains 1:
>>> print(empty_list)
[1]
When we use .append() on a list that already has elements, our new
element is added to the end of the list:
# Create a list
my_list = [1, 2, 3]
# Append a number
my_list.append(5)
print(my_list) # check the result
the output looks like:
[1, 2, 3, 5]
It’s important to remember that .append() comes after the list. This is
different from functions like print, which come before.
Instructions
[Link] works for a gardening store called Petal Power. He keeps a record of
orders in a list called orders.
Use print to inspect the orders he has received today.
[Link] just received a new order for 'tulips'. Use append to add this string
to orders.
[Link] order has come in! Use append to add 'roses' to orders.
[Link] print to inspect the orders Jiho has received today.
orders = ['daisies', 'periwinkle']
print(orders)
[Link]('tulips')
[Link]('roses')
print(orders)
Growing a List: Plus (+)
my_list + [4]
Instructions
[Link] is still updating his list of orders. He just received orders
for 'lilac' and 'iris'.
Use + to create a new list called new_orders that combines orders with the
two new orders.
[Link] the # in front of the list broken_prices. If you run this code, you’ll
get an error:
TypeError: can only concatenate list (not "int") to list
Fix the command by inserting brackets ([ and ]) so that it will run without
errors.
orders = ['daisy', 'buttercup', 'snapdragon', 'gardenia', 'lily']
new_orders = orders + ['lilac', 'iris']
print(new_orders)
broken_prices = [5, 3, 4, 5, 4] + [4]
print(broken_prices)
Range I
Often, we want to create a list of consecutive numbers. For example,
suppose we want a list containing the numbers 0 through 9:
my_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Typing out all of those numbers takes time and the more numbers we type,
the more likely it is that we have a typo.
Python gives us an easy way of creating these lists using a function
called range. The function range takes a single input, and generates
numbers starting at 0 and ending at the number before the input. So, if we
want the numbers from 0 through 9, we use range(10) because 10 is 1
greater than 9:
my_range = range(10)
Just like with zip, the range function returns an object that we can convert
into a list:
>>> print(my_range)
range(0, 10)
>>> print(list(my_range))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Instructions
[Link] list1 so that it is a range containing numbers starting at 0 and up
to, but not including, 9.
[Link] a range called range1 with the numbers 0 through 7.
list1 = range(9)
range1 = range(8)
Range II
We can use range to generate more interesting lists.
By default, range creates a list starting at 0. However, if we call range with
two arguments, we can create a list that starts at a different number. For
example, range(2, 9) would generate numbers starting at 2 and ending
at 8 (just before 9):
>>> my_list = range(2, 9)
>>> print(list(my_list))
[2, 3, 4, 5, 6, 7, 8]
With one or two arguments, range will create a list of consecutive numbers
(i.e., each number is one greater than the previous number). If we use a
third argument, we can create a list that “skips” numbers. For
example, range(2, 9, 2) will give us a list where each number is 2 greater
than the previous number:
>>> my_range2 = range(2, 9, 2)
>>> print(list(my_range2))
[2, 4, 6, 8]
We can skip as many numbers as we want! In this example, we’ll start
at 1 and skip 10 between each number until we get to 100:
>>> my_range3 = range(1, 100, 10)
>>> print(list(my_range3))
[1, 11, 21, 31, 41, 51, 61, 71, 81, 91]
Our list stops at 91 because the next number in the sequence would
be 101, which is greater than 100 (our stopping point).
Instructions
[Link] the range function that created list1 such that it:
Starts at 5
Has a difference of 3 between each item
Ends before 15
[Link] a range object called list2 that:
Starts at 0
Has a difference of 5 between each item
Ends before 40
list1 = range(5, 15, 3)
list2 = range(0, 40, 5)
Review
Instructions
[Link] is entering customer data for her web design business. You’re
going to help her organize her data.
Start by turning this list of customer first names into a list
called first_names:
Ainsley
Ben
Chani
Depak
[Link] an empty list called age.
[Link] .append() to add the age 42 to age.
[Link] a new list called all_ages that combines age with the following list:
[32, 41, 29]
[Link] a new variable called name_and_age that
combines first_names and all_ages using zip.
[Link] a range object called ids with an id number for each customer.
There are 4 customers, so your range should be from 0 to 3.
first_names = ['Ainsley', 'Ben', 'Chani', 'Depak']
age = []
[Link](42)
all_ages = age + [32, 41, 29]
name_and_age = zip(first_names, all_ages)
ids = range(4)
Python Gradebook
You are a student and you are trying to organize your subjects and grades
using Python. Let’s explore what we’ve learned about lists to organize your
subjects and scores.
Tasks
Create Some Lists:
[Link] a list called subjects and fill it with the classes you are taking:
"physics"
"calculus"
"poetry"
"history"
[Link] a list called grades and fill it with your scores:
98
97
85
88
[Link] the zip() function to combine subjects and grades.
Save this zip object as a list into a variable called gradebook.
[Link] gradebook.
[Link] grade for Computer Science class just came in! You got a perfect
score, 100!
After your definitions of subjects and grades but before you
create gradebook, use append to add "computer
science" to subjects and 100 to grades.
[Link] grade for visual arts just came in! You got a 93!
After the creation of gradebook (but before you print it out), use append to
add ("visual arts", 93) to gradebook.
[Link] also have your grades from last semester, stored
in last_semester_gradebook. Create a new variable full_gradebook with the
items from both gradebook and last_semester_gradebook.
last_semester_gradebook = [("politics", 80), ("latin", 96), ("dance", 97),
("architecture", 65)]
subjects = ["physics", "calculus", "poetry", "history"]
grades = [98, 97, 85, 88]
[Link]("computer science")
[Link](100)
gradebook = list(zip(grades, subjects))
[Link](("visual arts", 93))
print(list(gradebook))
Length of a List
Often, we’ll need to find the number of items in a list, usually called
its length.
We can do this using the function len. When we apply len to a list, we get
the number of elements in that list:
my_list = [1, 2, 3, 4, 5]
print(len(my_list))
This would yield:
5
Instructions
[Link] the length of list1 and save it to the variable list1_len.
[Link] print to examine list1_len.
[Link] the range command that generates list1 so that it skips 3 instead
of 2 between items.
How does this change list1_len?
list1 = range(2, 20, 3)
list1_len = len(list1)
print(list1_len)
Selecting List Elements I
Chris is interviewing candidates for a job. He will call each candidate in
order, represented by a Python list:
calls = ['Ali', 'Bob', 'Cam', 'Doug', 'Ellie']
First, he’ll call 'Ali', then 'Bob', etc.
In Python, we call the order of an element in a list its index.
Python lists are zero-indexed. This means that the first element in a list has
index 0, rather than 1.
Here are the index numbers for that list:
Element Index
‘Ali’ 0
‘Bob’ 1
‘Cam’ 2
‘Doug’ 3
‘Ellie’ 4
In this example, the element with index 2 is 'Cam'.
We can select a single element from a list by using square brackets ([]) and
the index of the list item. For example, if we wanted to select the third
element from the list, we’d use calls[2]:
>>> print(calls[2])
'Cam'
Instructions
[Link] square brackets ([ and ]) to select the element with index 4 from the
list employees. Save it to the variable index4.
[Link] print and len to display how many items are in employees.
[Link] the following code into [Link]:
print(employees[8])
What happens? Why?
[Link] an element that does not exist produces an IndexError.
In the line of code that you pasted, change 8 to a different number so that
you don’t get an IndexError.
employees = ['Michael', 'Dwight', 'Jim', 'Pam', 'Ryan', 'Andy', 'Robert']
index4 = employees[4]
print(len(employees))
print(employees[5])
Selecting List Elements II
What if we want to select the last element of a list?
We can use the index -1 to select the last item of a list, even when we don’t
know how many elements are in a list.
Consider the following list with 5 elements:
list1 = ['a', 'b', 'c', 'd', 'e']
If we select the -1 element, we get the final element, 'e':
>>> print(list1[-1])
'e'
This is the same as selecting the element with index 4:
>>> print(list1[4])
'e'
Instructions
[Link] print and len to display the length of shopping_list.
[Link] the last element of shopping_list using the -1 index. Save this
element to the variable last_element.
[Link] select the element with index 5 and save it to the variable element5.
[Link] print to display both element5 and last_element.
shopping_list = ['eggs', 'butter', 'milk', 'cucumbers', 'juice', 'cereal']
print(len(shopping_list))
last_element = shopping_list[-1]
element5 = shopping_list[5]
print(last_element)
print(element5)
Slicing Lists
Suppose we have a list of letters:
letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
Suppose we want to select from b through f.
We can do this using the following syntax: letters[start:end], where:
start is the index of the first element that we want to include in our
selection. In this case, we want to start at b, which has index 1.
end is the index of one more than the last index that we want to
include. The last element we want is f, which has index 5,
so end needs to be 6.
sublist = letters[1:6]
print(sublist)
This example would yield:
['b', 'c', 'd', 'e', 'f']
Notice that the element at index 6 (which is g) is not included in our
selection.
Creating a selection from a list is called slicing.
Instructions
[Link] print to examine the variable beginning.
How many elements does it contain?
[Link] beginning, so that it selects the first 4 elements of suitcase.
[Link] a new list called middle that contains the middle two items
from suitcase.
suitcase = ['shirt', 'shirt', 'pants', 'pants', 'pajamas', 'books']
beginning = suitcase[0:4]
print(beginning)
middle = suitcase[2:4]
Slicing Lists II
If we want to select the first 3 elements of a list, we could use the following
code:
>>> fruits = ['apple', 'banana', 'cherry', 'date']
>>> print(fruits[0:3])
['apple', 'banana', 'cherry']
When starting at the beginning of the list, it is also valid to omit the 0:
>>> print(fruits[:3])
['apple', 'banana', 'cherry']
We can do something similar when selecting the last few items of a list:
>>> print(fruits[2:])
['cherry' , 'date']
We can omit the final index when selecting the final elements from a list.
If we want to select the last 3 elements of fruits, we can also use this syntax:
>>> print(fruits[-3:])
['banana', 'cherry', 'date']
We can use negative indexes to count backward from the last element.
Instructions
[Link] a new list called start containing the first 3 elements of suitcase.
[Link] a new list called end containing the final two elements of suitcase.
suitcase = ['shirt', 'shirt', 'pants', 'pants', 'pajamas', 'books']
start = suitcase[:3]
end = suitcase[-2:]
Counting elements in a list
Suppose we have a list called letters that represents the letters in the word
“Mississippi”:
letters = ['m', 'i', 's', 's', 'i', 's', 's', 'i', 'p', 'p', 'i']
If we want to know how many times i appears in this word, we can use the
function count:
num_i = [Link]('i')
print(num_i)
This would print out:
4
Instructions
[Link]. WIlson’s class is voting for class president. She has saved each
student’s vote into the list votes.
Use count to determine how many students voted for 'Jake'. Save your
answer as jake_votes.
[Link] print to examine jake_votes.
votes = ['Jake', 'Jake', 'Laurie', 'Laurie', 'Laurie', 'Jake', 'Jake', 'Jake',
'Laurie', 'Cassie', 'Cassie', 'Jake', 'Jake', 'Cassie', 'Laurie', 'Cassie', 'Jake',
'Jake', 'Cassie', 'Laurie']
jake_votes = [Link]('Jake')
print(jake_votes)
Sorting Lists I
Sometimes, we want to sort a list in either numerical (1, 2, 3, …) or
alphabetical (a, b, c, …) order.
We can sort a list in place using .sort(). Suppose that we have a list of
names:
names = ['Xander', 'Buffy', 'Angel', 'Willow', 'Giles']
print(names)
This would print:
['Xander', 'Buffy', 'Angel', 'Willow', 'Giles']
Now we apply .sort():
[Link]()
print(names)
And we get:
['Angel', 'Buffy', 'Giles', 'Willow', 'Xander']
Notice that sort goes after our list, names. If we try sort(names), we will get
a NameError.
sort does not return anything. So, if we try to assign [Link]() to a
variable, our new variable would be None:
sorted_names = [Link]()
print(sorted_names)
This prints:
None
Although sorted_names is None, the line sorted_names = [Link]() still
edited names:
>>> print(names)
['Angel', 'Buffy', 'Giles', 'Willow', 'Xander']
Instructions
[Link] sort to sort addresses.
[Link] print to see how addresses changed.
[Link] the # in front of the line sort(names). Edit this line so that it runs
without producing a NameError.
[Link] print to examine sorted_cities. Why is it not the sorted version
of cities?
addresses = ['221 B Baker St.', '42 Wallaby Way', '12 Grimmauld
Place', '742 Evergreen Terrace', '1600 Pennsylvania Ave', '10 Downing
St.']
[Link]()
print(addresses)
names = ['Ron', 'Hermione', 'Harry', 'Albus', 'Sirius']
[Link]()
cities = ['London', 'Paris', 'Rome', 'Los Angeles', 'New York']
sorted_cities = [Link]()
print(sorted_cities)
Sorting Lists II
A second way of sorting a list is to use sorted. sorted is different
from .sort() in several ways:
1. It comes before a list, instead of after.
2. It generates a new list.
Let’s return to our list of names:
names = ['Xander', 'Buffy', 'Angel', 'Willow', 'Giles']
Using sorted, we can create a new list, called sorted_names:
sorted_names = sorted(names)
print(sorted_names)
This yields the list sorted alphabetically:
['Angel', 'Buffy', 'Giles', 'Willow', 'Xander']
Note that using sorted did not change names:
>>> print(names)
['Xander', 'Buffy', 'Angel', 'Willow', 'Giles']
Instructions
[Link] sorted to order games and create a new list called games_sorted.
[Link] print to inspect games and games_sorted. How are they different?
games = ['Portal', 'Minecraft', 'Pacman', 'Tetris', 'The Sims',
'Pokemon']
games_sorted = sorted(games)
print(games)
print(games_sorted)
Review
Instructions
[Link] is a list of items that are in the warehouse for Bob’s Furniture.
How many items are in the warehouse?
Save your answer to inventory_len.
[Link] the first element in inventory. Save it to the variable first.
[Link] the last item from inventory and save it to the variable last.
[Link] items from the inventory starting at index 2 and up to, but not
including, index 6.
Save your answer to inventory_2_6.
[Link] the first 3 items of inventory and save it to the variable first_3.
[Link] many 'twin bed's are in inventory? Save your answer to twin_beds.
[Link] inventory using .sort().
inventory = ['twin bed', 'twin bed', 'headboard', 'queen bed', 'king
bed', 'dresser', 'dresser', 'table', 'table', 'nightstand', 'nightstand',
'king bed', 'king bed', 'twin bed', 'twin bed', 'sheets', 'sheets', 'pillow',
'pillow']
inventory_len = len(inventory)
first = inventory[0]
last = inventory[-1]
inventory_2_6 = inventory[2:6]
first_3 = inventory[:3]
twin_beds = [Link]('twin bed')
[Link]()
Len's Slice
Make Some Pizzas
[Link] keep track of the kinds of pizzas you sell, create a list
called toppings that holds the following:
pepperoni, pineapple, cheese, sausage, olives,anchovies, mushrooms
[Link] keep track of how much each kind of pizza slice costs, create a list
called prices that holds:
2,6,1,3,2,7,2
[Link] the length of the toppings list and store it in a variable
called num_pizzas.
[Link] the string "We sell X different kinds of pizza!",
with num_pizzas where the X is.
[Link] zip to combine the two lists into a list called pizzas that has the
structure:
[(price_0, topping_0), (price_1, topping_1), (price_2, topping_2), ...]
In order to make the result of zip a list, do the following:
list(zip(____, ____))
[Link] pizzas.
Sorting and Slicing Pizzas
[Link] pizzas so that the pizzas with the lowest prices are at the start of the
list.
[Link] the first element of pizzas in a variable called cheapest_pizza.
9.A man in a business suit walks in and shouts “I will have your MOST
EXPENSIVE pizza!”
Get the last item of the pizzas list and store it in a variable
called priciest_pizza.
[Link] mice walk into the store. They don’t have much money (they’re
mice), but they do each want different pizzas.
Slice the pizzas list and store the 3 lowest cost pizzas in a list
called three_cheapest.
[Link] the three_cheapest list.
[Link] boss wants you to do some research on $2 slices.
Count the number of occurrences of 2 in the prices list, and store the result
in a variable called num_two_dollar_slices. Print it out.
toppings = ['pepperoni', 'pineapple', 'cheese', 'sausage', 'olives',
'anchovies', 'mushrooms']
prices = [2, 6, 1, 3, 2, 7, 2]
num_pizzas = len(toppings)
print("We sell " + str(num_pizzas) + " different kinds of pizza!")
pizzas = list(zip(prices, toppings))
print(pizzas)
[Link]()
cheapest_pizza = pizzas[0]
priciest_pizza = pizzas[-1]
three_cheapest = pizzas[:3]
print(three_cheapest)
num_two_dollar_slices = [Link](2)
print(num_two_dollar_slices)
Double Index
double_index(lst, index)
Instructions
[Link] a function named double_index that has two parameters
named lst and index.
The function should return a new list where all elements are the same as
in lst except for the element at index, which should be double the value of
the element at index of lst.
If index is not a valid index, the function should return the original list.
For example, the following code should return [1,2,6,4] because the
element at index 2 has been doubled:
double_index([1, 2, 3, 4], 2)
After writing your function, un-comment the call to the function that we’ve
provided for you to test your results.
def double_index(lst, index):
if index >= len(lst):
return lst
else:
new_lst = lst[0:index]
new_lst.append(lst[index]*2)
new_lst = new_lst + lst[index+1:]
return new_lst
print(double_index([3, 8, -10, 12], 2))
Remove Middle
remove_middle(lst, start, end)
Instructions
[Link] a function named remove_middle which has three parameters
named lst, start, and end.
The function should return a list where all elements in lst with an index
between start and end (inclusive) have been removed.
For example, the following code should return [4, 23, 42] because elements
at indices 1, 2, and 3 have been removed:
remove_middle([4, 8 , 15, 16, 23, 42], 1, 3)
def remove_middle(lst, start, end):
return lst[:start] + lst[end+1:]
print(remove_middle([4, 8, 15, 16, 23, 42], 1, 3))
More Than N
more_than_n(lst, item, n)
Instructions
[Link] a function named more_than_n that has three parameters
named lst, item, and n.
The function should return True if item appears in the list more
than n times. The function should return False otherwise.
def more_than_n(lst, item, n):
if [Link](item) > n:
return True
else:
return False
print(more_than_n([2, 4, 6, 2, 3, 2, 1, 2], 2, 3))
More Frequent Item
more_frequent_item(lst, item1, item2)
Instructions
[Link] a function named more_frequent_item that has three parameters
named lst, item1, and item2.
Return either item1 or item2 depending on which item appears more often
in lst.
If the two items appear the same number of times, return item1.
def more_frequent_item(lst, item1, item2):
if [Link](item1) >= [Link](item2):
return item1
else:
return item2
print(more_frequent_item([2, 3, 3, 2, 3, 2, 3, 2, 3], 2, 3))
Middle Item
middle_element(lst)
Instructions
[Link] a function called middle_element that has one parameter
named lst.
If there are an odd number of elements in lst, the function should return
the middle element. If there are an even number of elements, the function
should return the average of the middle two elements.
def middle_element(lst):
if len(lst) % 2 == 0:
sum = lst[int(len(lst)/2)] + lst[int(len(lst)/2) - 1]
return sum / 2
else:
return lst[int(len(lst)/2)]
print(middle_element([5, 2, -10, -4, 4, 5]))
Append Sum
append_sum(lst)
Instructions
[Link] a function named append_sum that has one parameter named lst.
The function should add the last two elements of lst together and append
the result to lst. It should do this process three times and then return lst.
For example, if lst started as [1, 1, 2], the final result should be [1, 1, 2, 3, 5,
8].
def append_sum(lst):
[Link](lst[-1] + lst[-2])
[Link](lst[-1] + lst[-2])
[Link](lst[-1] + lst[-2])
return lst
print(append_sum([1, 1, 2]))
Larger List
larger_list(lst1, lst2)
Instructions
[Link] a function named larger_list that has two parameters
named lst1 and lst2.
The function should return the last element of the list that contains more
elements. If both lists are the same size, then return the last element of lst1.
def larger_list(lst1, lst2):
if len(lst1) >= len(lst2):
return lst1[-1]
else:
return lst2[-1]
print(larger_list([4, 10, 2, 5], [-10, 2, 5, 10]))
Combine Sort
combine_sort(lst1, lst2)
Instructions
[Link] a function named combine_sort that has two parameters
named lst1 and lst2.
The function should combine these two lists into one new list and sort the
result. Return the new sorted list.
def combine_sort(lst1, lst2):
unsorted = lst1 + lst2
sortedList = sorted(unsorted)
return sortedList
print(combine_sort([4, 10, 2, 5], [-10, 2, 5, 10]))
Append Size
append_size(lst)
Instructions
[Link] a function called append_size that has one parameter named lst.
The function should append the size of lst (inclusive) to the end of lst. The
function should then return this new list.
For example, if lst was [23, 42, 108], the function should return [23, 42, 108,
3] because the size of lst was originally 3.
def append_size(lst):
[Link](len(lst))
return lst
print(append_size([23, 42, 108]))
Every Three Nums
every_three_nums(start)
Instructions
[Link] a function called every_three_nums that has one parameter
named start.
The function should return a list of every third number
between start and 100 (inclusive). For
example, every_three_nums(91) should return the list [91, 94, 97, 100].
If start is greater than 100, the function should return an empty list.
def every_three_nums(start):
return list(range(start, 101, 3))
print(every_three_nums(91))
LOOPS
Introduction
Suppose we want to print() each item from a list of dog_breeds.
dog_breeds = ['french_bulldog', 'dalmatian', 'shihtzu', 'poodle', 'collie']
print(dog_breeds[0])
print(dog_breeds[1])
print(dog_breeds[2])
print(dog_breeds[3])
print(dog_breeds[4])
This seems inefficient. iterating ! A loop is a way of repeating a set of code
many times.
In this lesson, we’ll be learning about:
Loops that let us move through each item in a list, called for loops
Loops that keep going until we tell them to stop, called while loops
Loops that create new lists, called list comprehensions
Instructions
[Link] the following code into [Link]:
for breed in dog_breeds:
print(breed)
This will print each breed in dog_breeds.
dog_breeds = ['french_bulldog', 'dalmatian', 'shihtzu', 'poodle',
'collie']
for breed in dog_breeds:
print(breed)
Create a For Loop
In the previous exercise, we saw that we can print each item in a list using
a for loop. A for loop lets us perform an action on each item in a list. Using
each element of a list is known as iterating.
This loop prints each breed in dog_breeds:
dog_breeds = ['french_bulldog', 'dalmation', 'shihtzu', 'poodle', 'collie']
for breed in dog_breeds:
print(breed)
The general way of writing a for loop is:
for <temporary variable> in <list variable>:
<action>
In our dog breeds example, breed was the temporary
variable, dog_breeds was the list variable, and print(breed) was the action
performed on every item in the list.
Our temporary variable can be named whatever we want and does not
need to be defined beforehand. Each of the following code snippets does
the exact same thing as our example:
for i in dog_breeds:
print(i)
for dog in dog_breeds:
print(dog)
Instructions
[Link] the code. You should get an IndentationError because
the print(game) line is not indented.
[Link] line 6 so that you don’t get an IndentationError when you run the
code.
[Link] a loop that prints each sport in sport_games.
board_games = ['Settlers of Catan', 'Carcassone', 'Power Grid',
'Agricola', 'Scrabble']
sport_games = ['football', 'football - American', 'hockey', 'baseball',
'cricket']
for game in board_games:
print(game)
for games in sport_games:
print(games)
Using Range in Loops
Previously, we iterated through an existing list.
Often we won’t be iterating through a specific list, we’ll just want to do a
certain action multiple times. For example, if we wanted to print out
a "WARNING!" message three times, we would want to say something like:
for i in <a list of length 3>:
print("WARNING!")
Notice that we need to iterate through a list of length 3, but we don’t care
what’s in the list. To create these lists of length n, we can use
the range function. range takes in a number n as input, and returns a list
from 0 to n-1. For example:
zero_thru_five = range(6)
# zero_thru_five is now [0, 1, 2, 3, 4, 5]
zero_thru_one = range(2)
# zero_thru_one is now [0, 1]
So, an easy way to accomplish our "WARNING!" example would be:
for i in range(3):
print("WARNING!")
Instructions
[Link] the range function in a for loop to print out promise 5 times.
promise = "I will not chew gum in class"
for i in range(5):
print(promise)
Infinite Loops
We’ve iterated through lists that have a discrete beginning and end.
However, let’s consider this example:
my_favorite_numbers = [4, 8, 15, 16, 42]
for number in my_favorite_numbers:
my_favorite_numbers.append(1)
What happens here? Every time we enter the loop, we add a 1 to the end of
the list that we are iterating through. As a result, we never make it to the
end of the list! It keeps growing!
A loop that never terminates is called an infinite loop. These are very
dangerous for your code!
A program that hits an infinite loop often becomes completely unusable.
The best course of action is to never write an infinite loop. But if you
accidentally stumble into one, you can end the loop by using control + c to
terminate the program.
Instructions
[Link] we have two lists of
students, students_period_A and students_period_B. We want to combine
all students into students_period_B.
Write a for loop that goes through each student in students_period_A and
adds it to the end of students_period_B.
[Link] the for loop, after appending student to students_period_B,
print student.
[Link]’s suppose you made a typo in the body of your for loop. Oh no!
Inside the for loop, change the object of the append statement
from students_period_B to students_period_A.
Uh oh! Now you’re adding each student
in students_period_A to students_period_A! This will be infinite!
Refresh the page (or type something into your editor) to escape this infinite
loop! Then, get rid of the mistake that caused the infinite loop.
[Link] the fear of infinite loops instilled in you, change the
inner students_period_A back to students_period_B, if you haven’t already.
Revel in the safety of your code, and how it doesn’t crash your browser!
students_period_A = ["Alex", "Briana", "Cheri", "Daniele"]
students_period_B = ["Dora", "Minerva", "Alexa", "Obie"]
for student in students_period_A:
students_period_B.append(student)
print(student)
Break
We often want to use a for loop to search through a list for some value:
items_on_sale = ["blue_shirt", "striped_socks", "knit_dress", "red_headband",
"dinosaur_onesie"]
# we want to check if the item with ID "knit_dress" is on sale:
for item in items_on_sale:
if item == "knit_dress":
print("Knit Dress is on sale!")
This code goes through each item in items_on_sale and checks for a match.
After we find that "knit_dress" is in the list items_on_sale, we don’t need to
go through the rest of the items_on_sale list. Since it’s only 5 elements long,
iterating through the entire list is not a big deal in this case. But what
if items_on_sale had 1000 items after "knit_dress"? What if it had 100,000
items after "knit_dress"?
You can stop a for loop from inside the loop by using break. When the
program hits a break statement, control returns to the code outside of the
for loop. For example:
items_on_sale = ["blue_shirt", "striped_socks", "knit_dress", "red_headband",
"dinosaur_onesie"]
print("Checking the sale list!")
for item in items_on_sale:
print(item)
if item == "knit_dress":
break
print("End of search!")
This would produce the output:
Checking the sale list!
blue_shirt
striped_socks
knit_dress
End of search!
We didn’t need to check "red_headband" or "dinosaur_onesie" at all!
Instructions
[Link] have a list of dog breeds you can
adopt, dog_breeds_available_for_adoption. Using a for loop, iterate through
the dog_breeds_available_for_adoption list and print out each dog breed.
[Link] your for loop, after you print each dog breed, check if it is equal
to dog_breed_I_want. If so, print "They have the dog I want!"
[Link] a break statement when your loop has found dog_breed_I_want, so
that the rest of the list does not need to be checked.
dog_breeds_available_for_adoption = ['french_bulldog', 'dalmatian',
'shihtzu', 'poodle', 'collie']
dog_breed_I_want = 'dalmatian'
for breed in dog_breeds_available_for_adoption:
print(breed)
if breed == dog_breed_I_want:
print("They have the dog I want!")
break
Continue
When we’re iterating through lists, we may want to skip some values. Let’s
say we want to print out all of the numbers in a list, unless they’re negative.
We can use continue to move to the next i in the list:
big_number_list = [1, 2, -1, 4, -5, 5, 2, -9]
for i in big_number_list:
if i < 0:
continue
print(i)
This would produce the output:
1
2
4
5
2
Every time there was a negative number, the continue keyword moved the
index to the next value in the list, without executing the code in the rest of
the for loop.
Instructions
[Link] computer is the doorman at a bar in a country where the drinking
age is 21.
Loop through the ages list. If an entry is less than 21, skip it and move to
the next entry. Otherwise, print the age.
ages = [12, 38, 34, 26, 21, 19, 67, 41, 17]
for age in ages:
if age < 21:
continue
else:
print(age)
While Loops
We now have seen and used a lot of examples of for loops. There is another
type of loop we can also use, called a while loop. The while loop performs a
set of code until some condition is reached.
While loops can be used to iterate through lists, just like for loops:
dog_breeds = ['bulldog', 'dalmation', 'shihtzu', 'poodle', 'collie']
index = 0
while index < len(dog_breeds):
print(dog_breeds[index])
index += 1
Every time the condition of the while loop (in this case, index <
len(dog_breeds)) is satisfied, the code inside the while loop runs.
While loops can be useful when you don’t know how many iterations it will
take to satisfy a condition.
Instructions
[Link] are adding students to a Poetry class, the size of which is capped at
6. While the length of the students_in_poetry list is less than 6, use .pop() to
take a student off the all_students list and add it to
the students_in_poetry list.
[Link] the students_in_poetry list .
all_students = ["Alex", "Briana", "Cheri", "Daniele", "Dora", "Minerva",
"Alexa", "Obie", "Arius", "Loki"]
students_in_poetry = []
while len(students_in_poetry) < 6:
student = all_students.pop()
students_in_poetry.append(student)
print(students_in_poetry)
Nested Loops
We have seen how we can go through the elements of a list. What if we
have a list made up of multiple lists? How can we loop through all of the
individual elements?
Suppose we are in charge of a science class, that is split into three project
teams:
project_teams = [["Ava", "Samantha", "James"], ["Lucille", "Zed"], ["Edgar",
"Gabriel"]]
If we want to go through each student, we have to put one loop inside
another:
for team in project_teams:
for student in team:
print(student)
This results in:
Ava
Samantha
James
Lucille
Zed
Edgar
Gabriel
Instructions
[Link] have provided the list sales_data that shows the numbers of different
flavors of ice cream sold at three different locations of the fictional shop,
Gilbert and Ilbert’s Scoop Shop. We want to sum up the total number of
scoops sold. Start by defining a variable scoops_sold and set it to zero.
[Link] through the sales_data list. Call each inner list location, and print out
each location list.
[Link] the sales_data loop, go through each location list and add the
element to your scoops_sold variable.
By the end, you should have the sum of every number in
the sales_data nested list.
[Link] out the value of scoops_sold.
sales_data = [[12, 17, 22], [2, 10, 3], [5, 12, 13]]
scoops_sold = 0
for location in sales_data:
for item in location:
scoops_sold += item
print(scoops_sold)
List Comprehensions
Let’s say we have scraped a certain website and gotten these words:
words = ["@coolguy35", "#nofilter", "@kewldawg54", "reply", "timestamp",
"@matchamom", "follow", "#updog"]
We want to make a new list, called usernames, that has all of the strings
in words with an '@' as the first character. We know we can do this with a
for loop:
words = ["@coolguy35", "#nofilter", "@kewldawg54", "reply", "timestamp",
"@matchamom", "follow", "#updog"]
usernames = []
for word in words:
if word[0] == '@':
[Link](word)
First, we created a new empty list, usernames, and as we looped through
the words list, we added every word that matched our criterion. Now,
the usernames list looks like this:
>>> print(usernames)
["@coolguy35", "@kewldawg54", "@matchamom"]
Python has a convenient shorthand to create lists like this with one line:
usernames = [word for word in words if word[0] == '@']
This is called a list comprehension. It will produce the same output as the for
loop did:
["@coolguy35", "@kewldawg54", "@matchamom"]
This list comprehension:
1. Takes an element in words
2. Assigns that element to a variable called word
3. Checks if word[0] == '@', and if so, it adds word to the new
list, usernames. If not, nothing happens.
4. Repeats steps 1-3 for all of the strings in words
Instructions
[Link] have defined a list heights of visitors to a theme park. In order to ride
the Topsy Turvy Tumbletron roller coaster, you need to be above 161
centimeters. Using a list comprehension, create a new list
called can_ride_coaster that has every element from heights that is greater
than 161.
[Link] can_ride_coaster.
heights = [161, 164, 156, 144, 158, 170, 163, 163, 157]
can_ride_coaster = [item for item in heights if item > 161]
print(can_ride_coaster)
More List Comprehensions
Let’s say we’re working with the usernames list from the last exercise:
>>> print(usernames)
["@coolguy35", "@kewldawg54", "@matchamom"]
We want to create a new list with the string " please follow me!" added to
the end of each username. We want to call this new list messages. We can
use a list comprehension to make this list with one line:
messages = [user + " please follow me!" for user in usernames]
This list comprehension:
1. Takes a string in usernames
2. Assigns that number to a variable called user
3. Adds “ please follow me!” to user
4. Appends that concatenation to the new list called messages
5. Repeats steps 1-4 for all of the strings in usernames
Now, messages contains these values:
["@coolguy35 please follow me!", "@kewldawg54 please follow me!",
"@matchamom please follow me!"]
Being able to create lists with modified values is especially useful when
working with numbers. Let’s say we have this list:
my_upvotes = [192, 34, 22, 175, 75, 101, 97]
We want to add 100 to each value. We can accomplish this goal in one line:
updated_upvotes = [vote_value + 100 for vote_value in my_upvotes]
This list comprehension:
1. Takes a number in my_upvotes
2. Assigns that number to a variable called vote_value
3. Adds 100 to vote_value
4. Appends that sum to the new list updated_upvotes
5. Repeats steps 1-4 for all of the numbers in my_upvotes
Now, updated_upvotes contains these values:
[292, 134, 122, 275, 175, 201, 197]
Instructions
[Link] have provided a list of temperatures in celsius. Using a list
comprehension, create a new list called fahrenheit that converts each
element in the celsius list to fahrenheit.
temperature_in_fahrenheit = temperature_in_celsius * 9/5 + 32
[Link] fahrenheit.
celsius = [0, 10, 15, 32, -5, 27, 3]
fahrenheit = [item * (9/5) + 32 for item in celsius]
print(fahrenheit)
Review
Instructions
[Link] a list called single_digits that consists of the numbers 0-9
(inclusive).
[Link] a for loop that goes through single_digits and prints out each one.
[Link] a list called squares. Assign it to be an empty list to begin with.
[Link] the loop that iterates through single_digits, append the squared
value of each element of single_digits to the list squares. You can do this
before or after printing the element.
[Link] the for loop, print out squares.
[Link] the list cubes using a list comprehension on the single_digits list.
Each element of cubes should be an element of single_digits taken to the
third power.
[Link] cubes.
squares = []
single_digits = list(range(10))
for digit in single_digits:
print(digit)
[Link](digit**2)
print(squares)
cubes = [item ** 3 for item in single_digits]
print(cubes)
Carly's Clippers
You are the Data Analyst at Carly’s Clippers, the newest hair salon on the
block. Your job is to go through the lists of data that have been collected in
the past couple of weeks. You will be calculating some important metrics
that Carly can use to plan out the operation of the business for the rest of
the month.
You have been provided with three lists:
hairstyles: the names of the cuts offered at Carly’s Clippers
prices: the price of each hairstyle in the hairstyles list
last_week: the number of each hairstyle in hairstyles that was
purchased last week
Tasks
Prices and Cuts:
[Link] wants to be able to market her low prices. We want to find out what
the average price of a cut is.
First, let’s sum up all the prices of haircuts. Create a variable total_price, and
set it to 0.
[Link] through the prices list and add each price to the
variable total_price.
[Link] your loop, create a variable called average_price that is
the total_price divided by the number of prices.
You can get the number of prices by using the len() function.
[Link] the value of average_price so the output looks like:
Average Haircut Price: <average_price>
[Link] average price is more expensive than Carly thought it would be! She
wants to cut all prices by 5 dollars.
Use a list comprehension to make a list called new_prices, which has each
element in prices minus 5.
[Link] new_prices.
[Link] really wants to make sure that Carly’s Clippers is a profitable
endeavor. She first wants to know how much revenue was brought in last
week.
Create a variable called total_revenue and set it to 0.
[Link] a for loop to create a variable i that goes from 0 to len(hairstyles)
Hint: You can use range() to do this!
[Link] the product of prices[i] (the price of the haircut at position i)
and last_week[i] (the number of people who got the haircut at position i)
to total_revenue at each step.
[Link] your loop, print the value of total_revenue, so the output looks
like:
Total Revenue: <total_revenue>
[Link] the average daily revenue by dividing total_revenue by 7. Call this
number average_daily_revenue and print it out.
[Link] thinks she can bring in more customers by advertising all of the
haircuts she has that are under 30 dollars.
Use a list comprehension to create a list called cuts_under_30 that has the
entry hairstyles[i] for each i for which new_prices[i] is less than 30.
You can use range() in your list comprehension to make i go
from 0 to len(new_prices) - 1.
[Link] cuts_under_30.
hairstyles = ["bouffant", "pixie", "dreadlocks", "crew", "bowl", "bob",
"mohawk", "flattop"]
prices = [30, 25, 40, 20, 20, 35, 50, 35]
last_week = [2, 3, 5, 8, 4, 4, 6, 2]
total_price = 0
for price in prices:
total_price += price
average_price = total_price / len(prices)
print("Average Haircut Price: " + str(average_price))
new_prices = [price - 5 for price in prices]
print(new_prices)
total_revenue = 0
for i in range(len(hairstyles)):
total_revenue += prices[i] * last_week[i]
CODE CHALLENGE
Divisible by Ten
divisible_by_ten(nums)
Instructions
[Link] a function named divisible_by_ten() that takes a list of numbers
named nums as a parameter.
Return the count of how many numbers in the list are divisible by 10.
def divisible_by_ten(nums):
count = 0
for num in nums:
if num % 10 == 0:
count += 1
return count
print(divisible_by_ten([20, 25, 30, 35, 40]))
Greetings
add_greetings(names)
Instructions
[Link] a function named add_greetings() which takes a list of strings
named names as a parameter.
In the function, create an empty list that will contain each greeting. Add the
string "Hello, " in front of each name in names and append the greeting to
the list.
Return the new list containing the greetings.
def add_greetings(names):
new_list = []
for name in names:
new_list.append("Hello, " + name)
return new_list
print(add_greetings(["Owen", "Max", "Sophie"]))
Delete Starting Even Numbers
delete_starting_evens(lst)
Instructions
[Link] a function called delete_starting_evens() that has a parameter
named lst.
The function should remove elements from the front of lst until the front of
the list is not even. The function should then return lst.
For example if lst started as [4, 8, 10, 11, 12, 15],
then delete_starting_evens(lst) should return [11, 12, 15].
Make sure your function works even if every element in the list is even!
def delete_starting_evens(lst):
while (len(lst) > 0 and lst[0] % 2 == 0):
lst = lst[1:]
return lst
print(delete_starting_evens([4, 8, 10, 11, 12, 15]))
print(delete_starting_evens([4, 8, 10]))
Odd Indices
odd_indices(lst)
Instructions
[Link] a function named odd_indices() that has one parameter named lst.
The function should create a new empty list and add every element
from lst that has an odd index. The function should then return this new list.
For example, odd_indices([4, 3, 7, 10, 11, -2]) should return the list [3, 10,
-2].
def odd_indices(lst):
new_lst = []
for index in range(1, len(lst), 2):
new_lst.append(lst[index])
return new_lst
print(odd_indices([4, 3, 7, 10, 11, -2]))
Exponents
exponents(bases, powers)
Instructions
[Link] a function named exponents() that takes two lists as parameters
named bases and powers. Return a new list containing every number in
bases raised to every number in powers.
For example, consider the following code.
exponents([2, 3, 4], [1, 2, 3])
the result would be the list [2, 4, 8, 3, 9, 27, 4, 16, 64]. It would first add two
to the first. Then two to the second. Then two to the third, and so on.
def exponents(bases, powers):
new_lst = []
for base in bases:
for power in powers:
new_lst.append(base ** power)
return new_lst
print(exponents([2, 3, 4], [1, 2, 3]))
Larger Sum
larger_sum(lst1, lst2)
Instructions
[Link] a function named larger_sum() that takes two lists of numbers as
parameters named lst1 and lst2.
The function should return the list whose elements sum to the greater
number. If the sum of the elements of each list are equal, return lst1.
def larger_sum(lst1, lst2):
sum1 = 0
sum2 = 0
for number in lst1:
sum1 += number
for number in lst2:
sum2 += number
if sum1 >= sum2:
return lst1
else:
return lst2
print(larger_sum([1, 9, 5], [2, 3, 7]))
Over 9000
over_nine_thousand(lst)
Instructions
[Link] a function named over_nine_thousand() that takes a list of
numbers named lst as a parameter.
The function should sum the elements of the list until the sum is greater
than 9000. When this happens, the function should return the sum. If the
sum of all of the elements is never greater than 9000, the function should
return total sum of all the elements. If the list is empty, the function should
return 0.
For example, if lst was [8000, 900, 120, 5000], then the function should
return 9020.
def over_nine_thousand(lst):
sum = 0
for number in lst:
sum += number
if (sum > 9000):
break
return sum
print(over_nine_thousand([8000, 900, 120, 5000]))
Max Num
max_num(nums)
Instructions
[Link] a function named max_num() that takes a list of numbers
named nums as a parameter.
The function should return the largest number in nums
def max_num(nums):
maximum = nums[0]
for number in nums:
if number > maximum:
maximum = number
return maximum
print(max_num([50, -10, 0, 75, 20]))
Same Values
same_values(lst1, lst2)
Instructions
[Link] a function named same_values() that takes two lists of numbers of
equal size as parameters.
The function should return a list of the indices where the values were equal
in lst1 and lst2.
For example, the following code should return [0, 2, 3]
same_values([5, 1, -10, 3, 3], [5, 10, -10, 3, 5])
def same_values(lst1, lst2):
new_lst = []
for index in range(len(lst1)):
if lst1[index] == lst2[index]:
new_lst.append(index)
return new_lst
print(same_values([5, 1, -10, 3, 3], [5, 10, -10, 3, 5]))
Reversed List
reversed_list(lst1, lst2)
Instructions
[Link] a function named reversed_list() that takes two lists of the same
size as parameters named lst1 and lst2.
The function should return True if lst1 is the same as lst2 reversed. The
function should return False otherwise.
For example, reversed_list([1, 2, 3], [3, 2, 1]) should return True.
def reversed_list(lst1, lst2):
for index in range(len(lst1)):
if lst1[index] != lst2[len(lst2) - 1 - index]:
return False
return True
print(reversed_list([1, 2, 3], [3, 2, 1]))
print(reversed_list([1, 5, 3], [3, 2, 1]))
STRINGS
Introduction
Words and sentences are fundamental to how we communicate, so it
follows that we’d want our computers to be able to work with words and
sentences as well.
In Python, the way we store something like a word, a sentence, or even a
whole paragraph is as a string. A string is a sequence of characters. It can
be any length and can contain any letters, numbers, symbols, and spaces.
In this lesson, you will learn more about strings and how they are treated in
Python. You will learn how to slice strings, select specific characters from
strings, search strings for characters, iterate through strings, and use strings
in conditional statements.
Let’s get started.
Instructions
[Link] your favorite word as a string to the variable favorite_word.
[Link] favorite_word.
favorite_word = “Stiletto”
They're all Lists!
A string can be thought of as a list of characters.
Like any other list, each character in a string has an index. Consider the
string
favorite_fruit = "blueberry"
We can select specific letters from this string using the index. Let’s look at
the first letter of the string.
>>> favorite_fruit[1]
'l'
Whoops, is that the first letter you expected? Notice that the letter at
index 1 of "blueberry" isn’t b, it’s l. This is because the indices of a string
start at 0. b is located at the zero index and we could select it using:
>>> favorite_fruit[0]
'b'
It’s important to note that indices of strings must be integers. If you were to
try to select a non-integer index we would get a TypeError:
>>> favorite_fruit[1.5]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: string indices must be integers, not float
Instructions
[Link] of the most common things that are represented by strings are
names. Save your name as a string to the variable my_name.
[Link] the first letter of the variable my_name and save it to first_initial.
my_name = "Python Person"
first_initial = my_name[0]
Cut Me a Slice of String
Not only can we select a single character from a string, we can select entire
chunks of characters from a string. We can do this with the following
syntax:
string_name[first_index:last_index]
This is called slicing a string. When we slice a string we are creating
a new string that starts at (and includes) the first_index and ends at (but
excludes) the last_index. Let’s look at some examples of this. Recall our
favorite fruit:
>>> favorite_fruit
'blueberry'
The indices of this string are shown in the diagram below.
Let’s say we wanted a new string that contains the letters eberr. We could
slice favorite_fruit as follows:
>>> favorite_fruit[3:8]
'eberr'
Notice how the character at the first index, e, is INCLUDED, but the
character at the last index, y, is EXCLUDED. If you look for the indices 3 and
8 in the diagram, you can see how the y is outside that range.
We can also have open-ended selections. If we remove the first index, the
slice starts at the beginning of the string and if we remove the second
index the slice continues to the end of the string.
>>> favorite_fruit[:4]
'blue'
>>> favorite_fruit[4:]
'berry'
Again, notice how the b from berry is excluded from the first example and
included in the second example.
Instructions
[Link]’re a programmer working for Copeland’s Corporate Company. At this
company, each employee’s user name is generated by taking the first five
letters of their last name.
A new employee, Rodrigo Villanueva, is starting today and you need to
create his account. His first_name and last_name are stored as strings
in [Link].
Create a variable new_account by slicing the first five letters of
his last_name.
[Link] passwords for new employees are also generated from their
last names.
Create a variable called temp_password by creating a slice out of the third
through sixth letters of his last_name.
first_name = "Rodrigo"
last_name = "Villanueva"
new_account = last_name[:5]
temp_password = last_name[2:6]
Concatenating Strings
You can also concatenate two existing strings together into a new string.
Consider the following two strings.
fruit_prefix = "blue"
fruit_suffix = "berries"
We can create a new string by concatenating them together as follows:
favorite_fruit = fruit_prefix + fruit_suffix
>>> favorite_fruit
'blueberries'
Notice that there are no spaces added here. You have to manually add in
the spaces when concatenating strings if you want to include them.
fruit_sentence = "My favorite fruit is " + favorite_fruit
>>> fruit_sentence
'My favorite fruit is blueberries.`
Instructions
[Link]’s Corporate Company has realized that their policy of using the
first five letters of an employee’s last name as a user name isn’t ideal when
they have multiple employees with the same last name.
Write a function called account_generator that takes two
inputs, first_name and last_name and concatenates the first three letters of
each and then returns the new account name.
[Link] your function on the first_name and last_name provided
in [Link] and save it to the variable new_account
first_name = "Julie"
last_name = "Blevins"
def account_generator(first_name, last_name):
account_name = first_name[:3] + last_name[:3]
return account_name
new_account = account_generator(first_name, last_name)
print(new_account)
More and More String Slicing (How Long is that String?)
Python comes with some built-in functions for working with strings. One of
the most commonly used of these functions is len(). len() returns the
number of characters in a string
>>> favorite_fruit = "blueberry"
>>> len(favorite_fruit)
9
If you are taking the length of a sentence the spaces are counted as well.
>>> fruit_sentence = "I love blueberries"
>>> len(fruit_sentence)
18
len() comes in handy when we are trying to select the last character in a
string. You can try to run the following code:
>>> length = len(favorite_fruit)
>>> favorite_fruit[length]
But this code would generate an IndexError because, remember, the indices
start at 0, so the final character in a string has the index of len(string_name)
- 1.
>>> favorite_fruit[length-1]
'y'
You could also slice the last several characters of a string using len():
>>> favorite_fruit[length-4:]
'erry'
Using a len() statement as the starting index and omitting the final index
lets you slice n characters from the end of a string where n is the amount
you subtract from len().
Instructions
[Link]’s Corporate Company also wants to update how they generate
temporary passwords for new employees.
Write a function called password_generator that takes two
inputs, first_name and last_name and then concatenate the last three letters
of each and returns them as a string.
[Link] your function on the provided first_name and last_name and save it
to the variable temp_password.
first_name = "Reiko"
last_name = "Matsuki"
def password_generator(first_name, last_name):
temp_password = first_name[len(first_name)-3:] +
last_name[len(last_name)-3:]
return temp_password
temp_password = password_generator(first_name, last_name)
Negative Indices
In the previous exercise, we used len() to get a slice of characters at the end
of a string.
There’s a much easier way to do this, we can use negative indices! Negative
indices count backward from the end of the string, so string_name[-1] is the
last character of the string, string_name[-2] is the second last character of
the string, etc.
Here are some examples:
>>> favorite_fruit = 'blueberry`
>>> favorite_fruit[-1]
'y'
>>> favorite_fruit[-2]
'r'
>>> favorite_fruit[-3:]
'rry'
Notice that we are able to slice the last three characters of ‘blueberry’ by
having a starting index of -3 and omitting a final index.
Instructions
[Link] negative indices to find the the second to last character
in company_motto. Save this to the variable second_to_last.
[Link] negative indices to create a slice of the last 4 characters
in company_motto. Save this to the variable final_word.
company_motto = "Copeland's Corporate Company helps you capably
cope with the constant cacophony of daily life"
second_to_last = company_motto[-2]
final_word = company_motto[-4:]
Strings are Immutable
So far in this lesson, we’ve been selecting characters from strings, slicing
strings, and concatenating strings. Each time we perform one of these
operations we are creating an entirely new string.
This is because strings are immutable. This means that we cannot change a
string once it is created. We can use it to create other strings, but we
cannot change the string itself.
This property, generally, is known as mutability. Data types that
are mutable can be changed, and data types, like strings, that
are immutable cannot be changed.
Instructions
[Link] most recent hire at Copeland’s Corporate Company is a fellow named
Rob Daily. Unfortunately, Human Resources seem to have made a bit of a
typo and sent over the wrong first_name.
Try changing the first character of first_name by running
first_name[0] = "R"
[Link] right! Strings are immutable, so we can’t change an individual
character. Okay, that’s no problem we can still fix this!
Concatenate the string “R” with a slice of first_name that includes
everything but the first character and save it to a new
string fixed_first_name.
first_name = "Bob"
last_name = "Daily"
# first_name[0] = "R"
fixed_first_name = "R" + first_name[1:]
Iterating through Strings
Now you know enough about strings that we can start doing the really fun
stuff!
Because strings are lists, that means we can iterate through a string
using for or while loops. This opens up a whole range of possibilities of
ways we can manipulate and analyze strings. Let’s take a look at an
example.
def print_each_letter(word):
for letter in word:
print(letter)
This code will iterate through each letter in a given word and will print it to
the terminal.
>>> favorite_color = "blue"
>>> print_each_letter(favorite_color)
'b'
'l'
'u'
'e'
Let’s try a couple problems where we need to iterate through a string.
Instructions
[Link]’s replicate a function you are already familiar with, len().
Write a new function called get_length() that takes a string as an input and
returns the number of characters in that string. Do this by iterating through
the string, don’t cheat and use len()!
def get_length(word):
counter = 0
for letter in word:
counter += 1
return counter
Strings and Conditionals (Part One)
Now that we are iterating through strings, we can really explore the
potential of strings. When we iterate through a string we do something with
each character. By including conditional statements inside of these
iterations, we can start to do some really cool stuff.
Take a look at the following code:
favorite_fruit = "blueberry"
counter = 0
for character in favorite_fruit:
if character == "b":
counter = counter + 1
print(counter)
This code will count the number of bs in the string “blueberry” (hint: it’s
two). Let’s take a moment and break down what exactly this code is doing.
First, we define our string, favorite_fruit, and a variable called counter, which
we set equal to zero. Then the for loop will iterate through each character
in favorite_fruit and compare it to the letter b.
Each time a character equals b the code will increase the
variable counter by one. Then, once all characters have been checked, the
code will print the counter, telling us how many bs were in “blueberry”. This
is a great example of how iterating through a string can be used to solve a
specific application, in this case counting a certain letter in a word.
Instructions
[Link] a function called letter_check that takes two inputs, word and letter.
This function should return True if the word contains the letter and False if
it does not.
def letter_check(word, letter):
for character in word:
if character == letter:
return True
return False
Strings and Conditionals (Part Two)
There’s an even easier way than iterating through the entire string to
determine if a character is in a string. We can do this type of check more
efficiently using in. in checks if one string is part of another string.
Here is what the syntax of in looks like:
letter in word
Here, letter in word is a boolean expression that is True if the string letter is
in the string word. Here are some examples:
>>>"e" in "blueberry"
True
>>> "a" in "blueberry"
False
In fact, this method is more powerful than the function you wrote in the last
exercise because it works not only with letters, but with entire strings as
well.
>>> "blue" in "blueberry"
True
>>> "blue" in "strawberry"
False
Instructions
[Link] a function called contains that takes two
arguments, big_string and little_string and
returns True if big_string contains little_string.
For example contains("watermelon", "melon") should
return True and contains("watermelon", "berry") should return False.
[Link] a function called common_letters that takes two
arguments, string_one and string_two and then returns a list with all of the
letters they have in common.
The letters in the returned list should be unique. For example,
common_letters("banana", "cream")
should return ['a'].
def contains(big_string, little_string):
return little_string in big_string
def common_letters(string_one, string_two):
common = []
for letter in string_one:
if (letter in string_two) and not (letter in common):
[Link](letter)
return common
Review
Instructions
[Link]’s Corporate Company has finalized what they want to their
username and temporary password creation to be and have enlisted your
help, once again, to build the function to generate them. In this exercise,
you will create two
functions, username_generator and password_generator.
Let’s start with username_generator. Create a function
called username_generator take two inputs, first_name and last_name and
returns a username. The username should be a slice of the first three letters
of their first name and the first four letters of their last name. If their first
name is less than three letters or their last name is less than four letters it
should use their entire names.
For example, if the employee’s name is Abe Simpson the function should
generate the username AbeSimp.
[Link] work! Now for the temporary password, they want the function to
take the input user name and shift all of the letters by one to the right, so
the last letter of the username ends up as the first letter and so forth. For
example, if the username is AbeSimp, then the temporary password
generated should be pAbeSim.
Start by defining the function password_generator so that it takes one
input, username and in it define an empty string named password.
[Link] password_generator create a for loop that iterates through the
indices username by going from 0 to len(username).
To shift the letters right, at each letter the for loop should add the previous
letter to the string password.
def username_generator(first_name, last_name):
if len(first_name) < 3:
user_name = first_name
else:
user_name = first_name[0:3]
if len(last_name) < 4:
user_name += last_name
else:
user_name += last_name[0:4]
return user_name
def password_generator(user_name):
password = ""
for i in range(0, len(user_name)):
password += user_name[i-1]
return password
STRING METHODS
Introduction
Do you have a gigantic string that you need to parse for information? Do
you need to sanitize a users input to work in a function? Do you need to be
able to generate outputs with variable values? All of these things can be
accomplished with string methods!
Python comes with built-in string methods that gives you the power to
perform complicated tasks on strings very quickly and efficiently. These
string methods allow you to change the case of a string, split a string into
many smaller strings, join many small strings together into a larger string,
and allow you to neatly combine changing variables with string outputs.
In the previous lesson, you worked len(), which was a function that
determined the number of characters in a string. This, while similar, was
NOT a string method. String methods all have the same syntax:
py string_name.string_method(arguments)
Unlike len(), which is called with a string as it’s argument, a string method is
called at the end of a string and each one has its own method specific
arguments.
Formatting Methods
There are three string methods that can change the casing of a string.
These are .lower(), .upper(), and .title().
.lower() returns the string with all lowercase characters.
.upper() returns the string with all uppercase characters.
.title() returns the string in title case, which means the first letter of
each word is capitalized.
Here’s an example of .lower() in action:
>>> favorite_song = 'SmOoTH'
>>> favorite_song_lowercase = favorite_song.lower()
>>> favorite_song_lowercase
'smooth'
Every character was changed to lowercase! It’s important to remember that
string methods can only create new strings, they do not change the
original string.
>>> favorite_song
'SmOoTH'
See, it’s still the same! These string methods are great for sanitizing user
input and standardizing the formatting of your strings.
Instructions
[Link]’re a programmer working for an organization that is trying to digitize
and store poetry called Preserve the Verse.
You’ve been given two strings, the title of a poem and it’s author, and have
been asked to reformat them slightly to fit the conventions of the
organization’s database.
Make poem_title have title case and save it to poem_title_fixed.
[Link] poem_title and poem_title_fixed.
How did the string change?
[Link] organization’s database also needs the author’s name to be
uppercase only.
Make poem_author uppercase and save it to poem_author_fixed.
[Link] poem_author and poem_author_fixed.
Again, how did the string change?
poem_title = "spring storm"
poem_author = "William Carlos Williams"
poem_title_fixed = poem_title.title()
print(poem_title)
print(poem_title_fixed)
poem_author_fixed = poem_author.upper()
print(poem_author)
print(poem_author_fixed)
Splitting Strings
.upper(), .lower(), and .title() all are performed on an existing string and
produce a string in return. Let’s take a look at a string method that returns
a different object entirely!
.split() is performed on a string, takes one argument, and returns a list of
substrings found between the given argument (which in the case
of .split() is known as the delimiter). The following syntax should be used:
string_name.split(delimiter)
If you do not provide an argument for .split() it will default to splitting at
spaces.
For example, consider the following strings:
>>> man_its_a_hot_one = "Like seven inches from the midday sun"
>>> man_its_a_hot_one.split()
['Like', 'seven', 'inches', 'from', 'the', 'midday', 'sun']
.split returned a list with each word in the string. Important to note: if we
run .split() on a string with no spaces, we will get the same string in return.
Instructions
[Link] the code editor is a string of the first line of the poem Spring Storm by
William Carlos Williams.
Use .split() to create a list called line_one_words that contains each word in
this line of poetry.
line_one = "The sky has given over"
line_one_words = line_one.split()
Splitting Strings II
If we provide an argument for .split() we can dictate the character we want
our string to be split on. This argument should be provided as a string itself.
Consider the following example:
>>> greatest_guitarist = "santana"
>>> greatest_guitarist.split('n')
['sa', 'ta', 'a']
We provided 'n' as the argument for .split() so our string “santana” got split
at each 'n' character into a list of three strings.
What do you think happens if we split the same string at 'a'?
>>> greatest_guitarist.split('a')
['s', 'nt', 'n', ' ']
Notice that there is an unexpected extra '' string in this list. When you split
a string on a character that it also ends with, you’ll end up with an empty
string at the end of the list.
You can use any string as the argument for .split(), making it a versatile and
powerful tool.
Instructions
[Link] boss at the Poetry organization sent over a bunch of author names
that he wants you to prepare for importing into the database. Annoyingly,
he sent them over as a long string with the names separated by commas.
Using .split() and the provided string, create a list
called author_names containing each individual author name as it’s own
string.
[Link] work, but now it turns out they didn’t want poet’s first names (why
didn’t they just say that the first time!?)
Create another list called author_last_names that only contains the last
names of the poets in the provided string.
authors = "Audre Lorde,Gabriela Mistral,Jean Toomer,An Qi,Walt
Whitman,Shel Silverstein,Carmen Boullosa,Kamala Suraiyya,Langston
Hughes,Adrienne Rich,Nikki Giovanni"
author_names = [Link](',')
print(author_names)
author_last_names = []
for name in author_names:
author_last_names.append([Link]()[-1])
print(author_last_names)
Splitting Strings III
We can also split strings using escape sequences. Escape sequences are
used to indicate that we want to split by something in a string that is not
necessarily a character. The two escape sequences we will cover here are
\n Newline
\t Horizontal Tab
Newline or \n will allow us to split a multi-line string by line breaks
and \t will allow us to split a string by tabs. \t is particularly useful when
dealing with certain datasets because it is not uncommon for data points to
be separated by tabs.
Let’s take a look at an example of splitting by an escape sequence:
smooth_chorus = \
"""And if you said, "This life ain't good enough."
I would give my world to lift you up
I could change my life to better suit your mood
Because you're so smooth"""
chorus_lines = smooth_chorus.split('\n')
print(chorus_lines)
This code is splitting the multi-line string at the newlines (\n) which exist at
the end of each line and saving it to a new list called chorus_lines. Then it
prints chorus_lines which will produce the output
['And if you said, "This life ain\'t good enough."', 'I would give my world to
lift you up', 'I could change my life to better suit your mood', "Because
you're so smooth"]
The new list contains each line of the original string as it’s own smaller
string. Also, notice that Python automatically escaped the ' character when
it created the new list.
Instructions
[Link] organization has sent you over the full text for William Carlos
Williams poem Spring Storm. They want you to break the poem up into its
individual lines.
Create a list called spring_storm_lines that contains a string for each line
of Spring Storm.
spring_storm_text = \
"""The sky has given over
its bitterness.
Out of the dark change
all day long
rain falls and falls
as if it would never end.
Still the snow keeps
its hold on the ground.
But water, water
from a thousand runnels!
It collects swiftly,
dappled with black
cuts a way for itself
through green ice in the gutters.
Drop after drop it falls
from the withered grass-stems
of the overhanging embankment."""
spring_storm_lines = spring_storm_text.split('\n')
Joining Strings
Now that you’ve learned to break strings apart using .split(), let’s learn to
put them back together using .join(). .join() is essentially the opposite
of .split(), it joins a list of strings together with a given delimiter. The syntax
of .join() is:
'delimiter'.join(list_you_want_to_join)
Now this may seem a little weird, because with .split() the argument was the
delimiter, but now the argument is the list. This is because join is still a
string method, which means it has to act on a string. The string .join() acts
on is the delimiter you want to join with, therefore the list you want to join
has to be the argument.
This can be a bit confusing, so let’s take a look at an example.
>>> my_munequita = ['My', 'Spanish', 'Harlem', 'Mona', 'Lisa']
>>> ' '.join(my_munequita)
'My Spanish Harlem Mona Lisa'
We take the list of strings, my_munequita, and we joined it together with
our delimiter, ' ', which is a space. The space is important if you are trying to
build a sentence from words, otherwise, we would have ended up with:
>>> ''.join(my_munequita)
'MySpanishHarlemMonaLisa'
Instructions
[Link]’ve been provided with a list of words from the first line of Jean
Toomer’s poem Reapers.
Use .join() to combine these words into a sentence and save that sentence
as the string reapers_line_one.
reapers_line_one_words = ["Black", "reapers", "with", "the", "sound",
"of", "steel", "on", "stones"]
reapers_line_one = ' '.join(reapers_line_one_words)
Joining Strings II
In the last exercise, we joined together a list of words using a space as the
delimiter to create a sentence. In fact, you can use any string as a delimiter
to join together a list of strings. For example, if we have the list
>>> santana_songs = ['Oye Como Va', 'Smooth', 'Black Magic Woman',
'Samba Pa Ti', 'Maria Maria']
We could join this list together with ANY string. One often used string is a
comma , because then we can create a string of comma separated variables,
or CSV.
>>> santana_songs_csv = ','.join(santana_songs)
>>> santana_songs_csv
'Oye Como Va,Smooth,Black Magic Woman,Samba Pa Ti,Maria Maria'
You’ll often find data stored in CSVs because it is an efficient, simple file
type used by popular programs like Excel or Google Spreadsheets.
You can also join using escape sequences as the delimiter. Consider the
following example:
smooth_fifth_verse_lines = ['Well I\'m from the barrio', 'You hear my rhythm
on your radio', 'You feel the turning of the world so soft and slow', 'Turning
you \'round and \'round']
smooth_fifth_verse = '\n'.join(smooth_fifth_verse_lines)
print(smooth_fifth_verse)
This code is taking the list of strings and joining them using a newline \n as
the delimiter. Then it prints the result and produces the output:
Well I'm from the barrio
You hear my rhythm on your radio
You feel the turning of the world so soft and slow
Turning you 'round and 'round
Instructions
[Link]’ve been given a list, winter_trees_lines, that contains all the lines to
William Carlos Williams poem, Winter Trees. You’ve been asked to join
together the strings in the list together into a single string that can be used
to display the full poem. Name this string winter_trees_full.
Print your result to the terminal. Make sure that each line of the poem
appears on a new line in your string.
winter_trees_lines = ['All the complicated details', 'of the attiring and',
'the disattiring are completed!', 'A liquid moon', 'moves gently
among', 'the long branches.', 'Thus having prepared their buds',
'against a sure winter', 'the wise trees', 'stand sleeping in the cold.']
winter_trees_full = '\n'.join(winter_trees_lines)
print(winter_trees_full)
.strip()
When working with strings that come from real data, you will often find
that the strings aren’t super clean. You’ll find lots of extra whitespace,
unnecessary linebreaks, and rogue tabs.
Python provides a great method for cleaning strings: .strip(). Stripping a
string removes all whitespace characters from the beginning and end.
Consider the following example:
>>> featuring = " rob thomas "
>>> [Link]()
'rob thomas'
All the whitespace on either side of the string has been stripped, but the
whitespace in the middle has been preserved.
You can also use .strip() with a character argument, which will strip that
character from either end of the string.
>>> featuring = "!!!rob thomas !!!!!"
>>> [Link]('!')
'rob thomas '
By including the argument '!' we are able to strip all of the ! characters from
either side of the string. Notice that now that we’ve included an argument
we are no longer stripping whitespace, we are ONLY stripping the
argument.
Instructions
[Link] sent over another list containing all the lines to the Audre Lorde
poem, Love, Maybe. They want you to join together all of the lines into a
single string that can be used to display the poem again, but this time,
you’ve noticed that the list contains a ton of unnecessary whitespace that
doesn’t appear in the actual poem.
First, use .strip() on each line in the list to remove the unnecessary
whitespace and save it as a new list love_maybe_lines_stripped.
2..join() the lines in love_maybe_lines_stripped together into one large
multi-line string, love_maybe_full, that can be printed to display the poem.
Each line of the poem should show up on its own line.
[Link] love_maybe_full.
love_maybe_lines = ['Always ', ' in the middle of our bloodiest
battles ', 'you lay down your arms', ' like flowering mines ','\n'
,' to conquer me home. ']
love_maybe_lines_stripped = []
for line in love_maybe_lines:
love_maybe_lines_stripped.append([Link]())
love_maybe_full = '\n'.join(love_maybe_lines_stripped)
print(love_maybe_full)
Replace
The next string method we will cover is .replace(). Replace takes two
arguments and replaces all instances of the first argument in a string with
the second argument. The syntax is as follows
string_name.replace(character_being_replaced, new_character)
Great! Let’s put it in context and look at an example.
>>> with_spaces = "You got the kind of loving that can be so smooth"
>>> with_underscores = with_spaces.replace(' ', '_')
>>> with_underscores
'You_got_the_kind_of_loving_that_can_be_so_smooth'
Here we used .replace() to change every instance of a space in the string
above to be an underscore instead.
Instructions
[Link] poetry organization has sent over the bio for Jean Toomer as it
currently exists on their site. Notice that there was a mistake with his last
name and all instances of Toomer are lacking one o.
Use .replace() to change all instances of Tomer in the bio to Toomer. Save
the updated bio to the string toomer_bio_fixed.
toomer_bio = \
"""
Nathan Pinchback Tomer, who adopted the name Jean Tomer early in
his literary career, was born in Washington, D.C. in 1894. Jean is the
son of Nathan Tomer was a mixed-race freedman, born into slavery in
1839 in Chatham County, North Carolina. Jean Tomer is most well
known for his first book Cane, which vividly portrays the life of
African-Americans in southern farmlands.
"""
toomer_bio_fixed = toomer_bio.replace("Tomer", "Toomer")
.find()
Another interesting string method is .find(). .find() takes a string as an
argument and searching the string it was run on for that string. It then
returns the first index value where that string is located.
Here’s an example:
>>> 'smooth'.find('t')
'4'
We searched the string 'smooth' for the string 't' and found that it was at
the fourth index spot, so .find() returned 4.
You can also search for larger strings, and .find() will return the index value
of the first character of that string.
>>>"smooth".find('oo')
'2'
Notice here that 2 is the index of the first o.
Instructions
[Link] the code editor is the first line of Gabriela Mistral’s poem God Wills It.
At what index place does the word “disown” appear? Save that index place
to the variable disown_placement.
god_wills_it_line_one = "The very earth will disown you"
disown_placement = god_wills_it_line_one.find("disown")
.format()
Python also provides a handy string method for including variables in
strings. This method is .format(). .format() takes variables as an argument
and includes them in the string that it is run on. You include {} marks as
placeholders for where those variables will be imported.
Consider the following function:
def favorite_song_statement(song, artist):
return "My favorite song is {} by {}.".format(song, artist)
The function favorite_song_statement takes two arguments, song and artist,
then returns the a string that includes both of the arguments and prints a
sentence. Note: .format() can take as many arguments are there are {} in the
string it is run on, which in this case in two.
Here’s an example of the function being run:
>>> favorite_song_statement("Smooth", "Santana")
"My favorite song is Smooth by Santana"
Now you may be asking yourself, I could have written this function using
string concatenation instead of .format(), why is this method better? The
answer is legibility and reusability. It is much easier to picture the end
result .format() than it is to picture the end result of string concatenation
and legibility is everything. You can also reuse the same base string with
different variables, allowing you to cut down on unnecessary, hard to
interpret code.
Instructions
[Link] a function called poem_title_card that takes two
inputs poet and title. The function should use .format() to return the
following string:
The poem "[TITLE]" is written by [POET].
For example, if the function is given the inputs
poem_title_card("Walt Whitman", "I Hear America Singing")
It should return the string
The poem "I Hear America Singing" is written by Walt Whitman.
def poem_title_card(poet, title):
poem_desc = "The poem \"{}\" is written by {}".format(title, poet)
return poem_desc
.format() II
.format() can be made even more legible for other people reading your
code by including keywords. Previously with .format(), you had to make sure
that your variables appeared as arguments in the same order that you
wanted them to appear in the string, which just added unnecessary
complications when writing code.
By including keywords in the string and in the arguments, you can remove
that ambiguity. Let’s look at an example.
def favorite_song_statement(song, artist):
return "My favorite song is {song} by {artist}.".format(song=song,
artist=artist)
Now it is clear to anyone reading the string what it supposed to return,
they don’t even need to look at the arguments of .format() in order to get a
clear understanding of what is supposed to happen. You can even reverse
the order of artist and song in the code above and it will work the same
way. This makes writing AND reading the code much easier.
Instructions
[Link] function poem_description is supposed to use .format() to print out
some quick information about a poem, but it seems to be causing some
errors currently.
Fix the function by using keywords in the .format() method.
[Link] poem_description with the following arguments and save the results
to the variable my_beard_description:
author = "Shel Silverstein"
title = "My Beard"
original_work = "Where the Sidewalk Ends"
publishing_date = "1974"
def poem_description(publishing_date, author, title, original_work):
poem_desc = "The poem {title} by {author} was originally published
in {original_work} in {publishing_date}.".format(publishing_date =
publishing_date, author = author, title = title, original_work =
original_work)
return poem_desc
author = "Shel Silverstein"
title = "My Beard"
original_work = "Where the Sidewalk Ends"
publishing_date = "1974"
my_beard_description = poem_description(publishing_date, author,
title, original_work)
print(my_beard_description)
Review
Instructions
[Link] the Verse has one final task for you. They have delivered you a
string that contains a list of poems, titled highlighted_poems, they want to
highlight on the site, but they need your help to parse the string into
something that can display the name, title, and publication date of the
highlighted poems on the site.
First, start by printing highlighted_poems to the terminal and see how it
displays.
[Link] information for each poem is separated by commas, and within this
information is the title of the poem, the author, and the date of publication.
Start by splitting highlighted_poems at the commas and saving it
to highlighted_poems_list.
[Link] highlighted_poems_list, how does the structure of the data look
now?
[Link] that there is inconsistent whitespace in highlighted_poems_list.
Let’s clean that up.
Start by creating a new empty list, highlighted_poems_stripped.
Then, iterate through highlighted_poems_list using a for loop and for each
poem strip away the whitespace and append it to your new
list, highlighted_poems_stripped.
[Link] highlighted_poems_stripped.
Looks good! All the whitespace is cleaned up.
[Link] we want to break up all the information for each poem into it’s own
list, so we end up with a list of lists.
Create a new empty list called highlighted_poems_details.
[Link] through highlighted_poems_stripped and split each string around
the : characters and append the new lists into highlighted_poems_details.
[Link]! Now we want to separate out all of the titles, the poets, and the
publication dates into their own lists.
Create three new empty lists, titles, poets, and dates.
[Link] through highlighted_poems_details and for each list in the list
append the appropriate elements into the lists titles, poets, and dates.
For example, for the poem The Shadow (1915) by William Carlos Williams
your code should be adding "The Shadow" to titles, "William Carlos
Williams" to poets, and "1915" to dates.
[Link], write a for loop that uses either f-strings or .format() to prints out
the following string for each poem:
The poem TITLE was published by POET in DATE.
highlighted_poems = "Afterimages:Audre Lorde:1997, The
Shadow:William Carlos Williams:1915, Ecstasy:Gabriela Mistral:1925,
Georgia Dusk:Jean Toomer:1923, Parting Before Daybreak:An
Qi:2014, The Untold Want:Walt Whitman:1871, Mr. Grumpledump's
Song:Shel Silverstein:2004, Angel Sound Mexico City:Carmen
Boullosa:2013, In Love:Kamala Suraiyya:1965, Dream
Variations:Langston Hughes:1994, Dreamwood:Adrienne Rich:1987"
# print(highlighted_poems)
highlighted_poems_list = highlighted_poems.split(',')
# print(highlighted_poems_list)
highlighted_poems_stripped = []
for poem in highlighted_poems_list:
highlighted_poems_stripped.append([Link]())
# print(highlighted_poems_stripped)
highlighted_poems_details = []
for poem in highlighted_poems_stripped:
highlighted_poems_details.append([Link](':'))
titles = []
poets = []
dates = []
for poem in highlighted_poems_details:
[Link](poem[0])
[Link](poem[1])
[Link](poem[2])
for i in range(0,len(highlighted_poems_details)):
print('The poem {} was published by {} in {}'.format(titles[i], poets[i],
dates[i]))
Thread Shed
You’ve recently been hired as a cashier at the local sewing hobby
shop, Thread Shed. Some of your daily responsibilities involve tallying the
number of sales during the day, calculating the total amount of money
made, and keeping track of the names of the customers.
Unfortunately, the Thread Shed has an extremely out-dating register
system and stores all of the transaction information in one huge unwieldy
string called daily_sales.
All day, for each transaction, the name of the customer, amount spent,
types of thread purchased, and the date of sale is all recorded in this same
string. Your task is to use your Python skills to iterate through this string
and clean up each transaction and store all the information in easier to
access lists.
Tasks
Break up `daily_sales` in easy to understand lists `customers`, `sales`,
and `threads_sold`.
[Link], take a minute to inspect the string daily_sales in the code editor.
How is each transaction stored? How is each piece of data within the
transaction stored?
Start thinking about how we can split up this string into its individual pieces
of data.
[Link] looks like each transaction is separated from the next transaction by a ,,
and then each piece of data within a transaction is separated by the
artifact ;,;.
If we want to split up daily_sales into a list of individual transactions, we are
going to want to split by ,, but first, we need to replace the artifact ;,; to
something without a comma, so we don’t split any transactions themselves.
Replace all the instances of ;,; in daily_sales with some other character and
save the result to daily_sales_replaced.
[Link] we can split the string into a list of each individual transaction.
Split daily_sales_replaced around commas and save it to a new
list daily_transactions.
[Link] daily_transactions.
How does it look?
[Link] next step is to split each individual transaction into a list of its data
points.
First, define an empty list daily_transactions_split
[Link], iterate through daily_transactions (remember, this is a list of strings
currently), and for each transaction, split the string around whatever
character you replaced the ;,; artifacts with in Step 2.
Append each of these split strings (which are lists now) to our new
list daily_transactions_split.
[Link] daily_transactions_split.
How’s it looking?
[Link] looks like each data item has inconsistent whitespace around it. First,
define an empty list transactions_clean.
Now, Iterate through daily_transactions_split and for each transaction
iterate through the different data points and strip off any whitespace.
Add each of these cleaned up transactions to the new
list transactions_clean.
[Link] transactions_clean.
If you performed the last step correctly, you shouldn’t see any unnecessary
whitespace.
[Link] three empty lists. customers, sales, and thread_sold. We are
going to collect the individual data points for each transaction in these lists.
[Link], iterate through transactions_clean and for each transaction:
1. Append the customers name to customers.
2. Append the amount of the sale to sales.
3. Append the threads sold to thread_sold.
[Link] customers, sales, and thread_sold to make sure each list is what
you are expected.
Determine the total value of the days sales.
[Link] we want to know how much Thread Shed made in a day.
First, define a variable called total_sales and set it equal to 0.
[Link], consider the list sales. It is a list of strings that we want to sum. In
order for us to sum these values, we will have to remove the $, and set
them equal to floats.
Iterate through sales and for each item, strip off the $, set it equal to a float,
and add it to total_sales
[Link] total sales.
How much did we make today?
How much thread of any specific color was sold?
[Link], we want to determine how many of each color thread we sold
today. Let’s start with a single color, and then we’ll generalize it.
First, print out thread_sold and inspect it.
[Link] see that thread_sold is a list of strings, some are single colors and
some are multiple colors separated by the & character.
The end product we want here is a list that contains an item for each color
thread sold, so no strings that have multiple colors in them.
First, define an empty list thread_sold_split.
[Link], iterate through thread_sold. For each item, check if it is a single
color or multiple colors. If it is a single color, append that color
to thread_sold_split.
If it is multiple colors, first split the string around the & character and then
add each color indivudally to thread_sold_split.
[Link], now we have a list thread_sold_split that contains an entry with
the color of every thread sold today.
Define a function called color_count that takes one argument, color. The
function should iterate through thread_sold_split and count the number of
times the item is equal to argument, color. Then, it should return this count.
[Link] your new function by running color_count('white').
Your function should return 28.
[Link] a list called colors that stores all of the colored threads
that Thread Shed offers:
py colors = ['red','yellow','green','white','black','blue','purple']
[Link], using the list colors, the string method .format(), and the
function color_count, iterate through thread_sold_split and print a sentence
that says how many threads of each color were sold today.
Thread Shed sold 28 threads of white thread today.
daily_sales = \
"""Edith Mcbride ;,;$1.21 ;,; white ;,;
09/15/17 ,Herbert Tran ;,; $7.29;,;
white&blue;,; 09/15/17 ,Paul Clarke ;,;$12.52
;,; white&blue ;,; 09/15/17 ,Lucille Caldwell
;,; $5.13 ;,; white ;,; 09/15/17,
Eduardo George ;,;$20.39;,; white&yellow
;,;09/15/17 , Danny Mclaughlin;,;$30.82;,;
purple ;,;09/15/17 ,Stacy Vargas;,; $1.85 ;,;
purple&yellow ;,;09/15/17, Shaun Brock;,;
$17.98;,;purple&yellow ;,; 09/15/17 ,
Erick Harper ;,;$17.41;,; blue ;,; 09/15/17,
Michelle Howell ;,;$28.59;,; blue;,; 09/15/17 ,
Carroll Boyd;,; $14.51;,; purple&blue ;,;
09/15/17 , Teresa Carter ;,; $19.64 ;,;
white;,;09/15/17 , Jacob Kennedy ;,; $11.40
;,; white&red ;,; 09/15/17, Craig Chambers;,;
$8.79 ;,; white&blue&red ;,;09/15/17 , Peggy Bell;,; $8.65 ;,;blue ;,;
09/15/17, Kenneth Cunningham ;,; $10.53;,; green&blue ;,;
09/15/17 , Marvin Morgan;,; $16.49;,;
green&blue&red ;,; 09/15/17 ,Marjorie Russell
;,; $6.55 ;,; green&blue&red;,; 09/15/17 ,
Israel Cummings;,; $11.86 ;,;black;,;
09/15/17, June Doyle ;,; $22.29 ;,;
black&yellow ;,;09/15/17 , Jaime Buchanan ;,;
$8.35;,; white&black&yellow ;,; 09/15/17,
Rhonda Farmer;,;$2.91 ;,; white&black&yellow
;,;09/15/17, Darren Mckenzie ;,;$22.94;,;green
;,;09/15/17,Rufus Malone;,;$4.70 ;,; green&yellow
;,; 09/15/17 ,Hubert Miles;,; $3.59
;,;green&yellow&blue;,; 09/15/17 , Joseph Bridges ;,;$5.66 ;,;
green&yellow&purple&blue
;,; 09/15/17 , Sergio Murphy ;,;$17.51 ;,;
black ;,; 09/15/17 , Audrey Ferguson ;,;
$5.54;,;black&blue ;,;09/15/17 ,Edna Williams ;,;
$17.13;,; black&blue;,; 09/15/17, Randy Fleming;,; $21.13
;,;black ;,;09/15/17 ,Elisa Hart;,; $0.35 ;,; black&purple;,; 09/15/17 ,
Ernesto Hunt ;,; $13.91 ;,; black&purple ;,;
09/15/17, Shannon Chavez ;,;$19.26 ;,;
yellow;,; 09/15/17 , Sammy Cain;,; $5.45;,;
yellow&red ;,;09/15/17 , Steven Reeves ;,;$5.50
;,; yellow;,; 09/15/17, Ruben Jones ;,;
$14.56 ;,; yellow&blue;,;09/15/17 , Essie Hansen;,; $7.33 ;,;
yellow&blue&red
;,; 09/15/17 , Rene Hardy ;,; $20.22 ;,;
black ;,; 09/15/17 , Lucy Snyder ;,; $8.67
;,;black&red ;,; 09/15/17 ,Dallas Obrien ;,;
$8.31;,; black&red ;,; 09/15/17, Stacey Payne
;,; $15.70 ;,; white&black&red ;,;09/15/17
, Tanya Cox ;,; $6.74 ;,;yellow ;,;
09/15/17 , Melody Moran ;,; $30.84
;,;yellow&black;,; 09/15/17 , Louise Becker ;,;
$12.31 ;,; green&yellow&black;,; 09/15/17 ,
Ryan Webster;,;$2.94 ;,; yellow ;,; 09/15/17
,Justin Blake ;,; $22.46 ;,;white&yellow ;,;
09/15/17, Beverly Baldwin ;,; $6.60;,;
white&yellow&black ;,;09/15/17 , Dale Brady
;,; $6.27 ;,; yellow ;,;09/15/17 ,Guadalupe Potter ;,;$21.12 ;,;
yellow;,; 09/15/17 ,
Desiree Butler ;,;$2.10 ;,;white;,; 09/15/17
,Sonja Barnett ;,; $14.22 ;,;white&black;,;
09/15/17, Angelica Garza;,;$11.60;,;white&black
;,; 09/15/17 , Jamie Welch ;,; $25.27 ;,;
white&black&red ;,;09/15/17 , Rex Hudson
;,;$8.26;,; purple;,; 09/15/17 , Nadine Gibbs
;,; $30.80 ;,; purple&yellow ;,; 09/15/17 ,
Hannah Pratt;,; $22.61 ;,; purple&yellow
;,;09/15/17,Gayle Richards;,;$22.19 ;,;
green&purple&yellow ;,;09/15/17 ,Stanley Holland
;,; $7.47 ;,; red ;,; 09/15/17 , Anna Dean;,;$5.49 ;,; yellow&red ;,;
09/15/17 ,
Terrance Saunders ;,; $23.70 ;,;green&yellow&red
;,; 09/15/17 , Brandi Zimmerman ;,; $26.66 ;,;
red ;,;09/15/17 ,Guadalupe Freeman ;,; $25.95;,;
green&red ;,; 09/15/17 ,Irving Patterson
;,;$19.55 ;,; green&white&red ;,; 09/15/17 ,Karl Ross;,; $15.68;,;
white ;,; 09/15/17 , Brandy Cortez ;,;$23.57;,;
white&red ;,;09/15/17,
Mamie Riley ;,;$29.32;,; purple;,;09/15/17 ,Mike Thornton ;,;
$26.44 ;,; purple ;,; 09/15/17,
Jamie Vaughn ;,; $17.24;,;green ;,; 09/15/17 ,
Noah Day ;,; $8.49 ;,;green ;,;09/15/17
,Josephine Keller ;,;$13.10 ;,;green;,; 09/15/17 , Tracey Wolfe;,;
$20.39 ;,; red ;,; 09/15/17 ,
Ignacio Parks;,;$14.70 ;,; white&red ;,;09/15/17
, Beatrice Newman ;,;$22.45 ;,;white&purple&red
;,; 09/15/17, Andre Norris ;,; $28.46 ;,;
red;,; 09/15/17 , Albert Lewis ;,; $23.89;,;
black&red;,; 09/15/17, Javier Bailey ;,;
$24.49 ;,; black&red ;,; 09/15/17 , Everett Lyons ;,;$1.81;,;
black&red ;,; 09/15/17 ,
Abraham Maxwell;,; $6.81 ;,;green;,; 09/15/17
, Traci Craig ;,;$0.65;,; green&yellow;,;
09/15/17 , Jeffrey Jenkins ;,;$26.45;,;
green&yellow&blue ;,; 09/15/17, Merle Wilson
;,; $7.69 ;,; purple;,; 09/15/17,Janis Franklin
;,;$8.74 ;,; purple&black ;,;09/15/17 ,
Leonard Guerrero ;,; $1.86 ;,;yellow
;,;09/15/17,Lana Sanchez;,;$14.75 ;,; yellow;,;
09/15/17 ,Donna Ball ;,; $28.10 ;,;
yellow&blue;,; 09/15/17 , Terrell Barber ;,;
$9.91 ;,; green ;,;09/15/17 ,Jody Flores;,;
$16.34 ;,; green ;,; 09/15/17, Daryl Herrera
;,;$27.57;,; white;,; 09/15/17 , Miguel Mcguire;,;$5.25;,;
white&blue ;,; 09/15/17 ,
Rogelio Gonzalez;,; $9.51;,; white&black&blue
;,; 09/15/17 , Lora Hammond ;,;$20.56 ;,;
green;,; 09/15/17,Owen Ward;,; $21.64 ;,;
green&yellow;,;09/15/17,Malcolm Morales ;,;
$24.99 ;,; green&yellow&black;,; 09/15/17 ,
Eric Mcdaniel ;,;$29.70;,; green ;,; 09/15/17
,Madeline Estrada;,; $15.52;,;green;,; 09/15/17
, Leticia Manning;,;$15.70 ;,; green&purple;,;
09/15/17 , Mario Wallace ;,; $12.36 ;,;green ;,;
09/15/17,Lewis Glover;,; $13.66 ;,;
green&white;,;09/15/17, Gail Phelps ;,;$30.52
;,; green&white&blue ;,; 09/15/17 , Myrtle Morris
;,; $22.66 ;,; green&white&blue;,;09/15/17"""
#------------------------------------------------
# Start coding below!
daily_sales_replaced = daily_sales.replace(“;,;”, “+”)
daily_transactions = daily_sales_replaced.split(“,”)
daily_transactions_split = []
for transactions in daily_transactions:
daily_transactions_split.sppend([Link](“+”))
print(daily_transactions_split)
transactions_clean = []
for transaction in daily_transactions_split:
transaction_clean = []
for data_point in transaction:
transaction_clean.append(data_point.replace(“\n”, “”).strip(“ “))
transaction_clean.append(transaction_clean)
print(transactions_clean)
customers = []
sales = []
thread_sold = []
for transaction in transaction_clean:
[Link](transaction[0])
[Link](transaction[1])
thread_sold.append(transaction[2])
total_sales = 0
for sale in sales:
total_sales += float([Link](“$”))
print(total_sales)
print(thread_sold)
thread_sold_split = []
for sale in thread_sold:
for color in [Link](“&”):
thread_sold_split.append(color)
def color_count(color):
color_total = 0
for thread_color in thread_sold_split:
if color == thread_color:
color_total += 1
return color_total
colors = [“red”, “yellow”, “green”, “white”, “black”, “blue”, “purple”]
for color in colors:
print(“Thread Shed sold {0} threads of {1} thread
today.”.format(color_count(color), color))
Count Letters
unique_english_letters(word)
Instructions
[Link] a function called unique_english_letters that takes the
string word as a parameter. The function should return the total number of
unique letters in the string. Uppercase and lowercase letters should be
counted as different letters.
We’ve given you a list of every uppercase and lower case letter in the
English alphabet. It will be helpful to include that list in your function.
letters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
def unique_english_letters(word):
uniques = 0
for letter in letters:
if letter in word:
uniques += 1
return uniques
print(unique_english_letters("mississippi"))
print(unique_english_letters("Apple"))
Count X
count_char_x()
Instructions
[Link] a function named count_char_x that takes a string named word and
a single character named x as parameters. The function should return the
number of times x appears in word.
def count_char_x(word, x):
occurrences = 0
for letter in word:
if letter == x:
occurrences += 1
return occurrences
print(count_char_x("mississippi", "s"))
print(count_char_x("mississippi", "m"))
Count Multi X
count_multi_char_x()
Instructions
[Link] a function named count_multi_char_x that takes a string
named word and a string named x. This function should do the same thing
as the count_char_x function you just wrote - it should return the number of
times x appears in word. However, this time, make sure your function works
when x is multiple characters long.
For example, count_multi_char_x("Mississippi", "iss") should return 2
def count_multi_char_x(word, x):
splits = [Link](x)
return(len(splits)-1)
print(count_multi_char_x("mississippi", "iss"))
print(count_multi_char_x("apple", "pp"))
Substring Between
substring_between_letters()
Instructions
[Link] a function named substring_between_letters that takes a string
named word, a single character named start, and another character
named end. This function should return the substring between the first
occurrence of start and end in word. If start or end are not in word, the
function should return word.
For example, substring_between_letters("apple", "p", "e") should return "pl".
def substring_between_letters(word, start, end):
start_ind = [Link](start)
end_ind = [Link](end)
if start_ind > -1 and end_ind > -1:
return(word[start_ind+1:end_ind])
return word
print(substring_between_letters("apple", "p", "e"))
print(substring_between_letters("apple", "p", "c"))
X Length
x_length_words()
Instructions
[Link] a function called x_length_words that takes a string
named sentence and an integer named x as parameters. This function
should return True if every word in sentence has a length greater than or
equal to x.
def x_length_words(sentence, x):
words = [Link](" ")
for word in words:
if len(word) < x:
return False
return True
print(x_length_words("i like apples", 2))
print(x_length_words("he likes apples", 2))
Check Name
check_for_name()
Instructions
[Link] a function called check_for_name that takes two strings as
parameters named sentence and name. The function should
return True if name appears in sentence in all lowercase letters, all
uppercase letters, or with any mix of uppercase and lowercase letters. The
function should return False otherwise.
For example, the following three calls should all return True:
check_for_name("My name is Jamie", "Jamie")
check_for_name("My name is jamie", "Jamie")
check_for_name("My name is JAMIE", "Jamie")
def check_for_name(sentence, name):
return [Link]() in [Link]()
print(check_for_name("My name is Jamie", "Jamie"))
print(check_for_name("My name is jamie", "Jamie"))
print(check_for_name("My name is Samantha", "Jamie"))
Every Other Letter
every_other_letter()
Instructions
[Link] a function named every_other_letter that takes a string
named word as a parameter. The function should return a string containing
every other letter in word.
Reverse
reverse_string()
Instructions
[Link] a function named reverse_string that has a string named word as a
parameter. The function should return word in reverse.
def reverse_string(word):
reverse = ""
for i in range(len(word)-1, -1, -1):
reverse += word[i]
return reverse
print(reverse_string("Codecademy"))
print(reverse_string("Hello world!"))
print(reverse_string(""))
Make Spoonerism
make_spoonerism()
Instructions
1.A Spoonerism is an error in speech when the first syllables of two words
are switched. For example, a Spoonerism is made when someone says
“Belly Jeans” instead of “Jelly Beans”.
Write a function called make_spoonerism that takes two strings as
parameters named word1 and word2. Finding the first syllable of a word is
a difficult task, so for our function, we’re going to switch the first letters of
each word. Return the two new words as a single string separated by a
space.
def make_spoonerism(word1, word2):
return word2[0]+word1[1:]+" "+word1[0]+word2[1:]
print(make_spoonerism("Codecademy", "Learn"))
print(make_spoonerism("Hello", "world!"))
print(make_spoonerism("a", "b"))
Add Exclamation
add_exclamation()
Instructions
[Link] a function named add_exclamation that has one parameter
named word. This function should add exclamation points to the end
of word until word is 20 characters long. If word is already at
least 20 characters long, just return word.
def add_exclamation(word):
while(len(word) < 20):
word += "!"
return word
print(add_exclamation("Codecademy"))
print(add_exclamation("Codecademy is the best place to learn"))
Modules
Modules Python Introduction
In the world of programming, we care a lot about making code reusable. In
most cases, we write code so that it can be reusable for ourselves. But
sometimes we share code that’s helpful across a broad range of situations.
In this lesson, we’ll explore how to use tools other people have built in
Python that are not included automatically for you when you install Python.
Python allows us to package code into files or sets of files called modules.
A module is a collection of Python declarations intended broadly to be
used as a tool. Modules are also often referred to as “libraries” or
“packages” — a package is really a directory that holds a collection of
modules.
Usually, to use a module in a file, the basic syntax you need at the top of
that file is:
from module_name import object_name
Often, a library will include a lot of code that you don’t need that may slow
down your program or conflict with existing code. Because of this, it makes
sense to only import what you need.
One common library that comes as part of the Python Standard Library
is datetime. datetime helps you work with dates and times in Python.
Let’s get started by importing and using the datetime module. In this case,
you’ll notice that datetime is both the name of the library and the name of
the object that you are importing.
Instructions
[Link] [Link] import the datetime type from the datetime library.
[Link] a variable current_time and set it equal to [Link]().
[Link] out current_time.
from datetime import datetime
current_time = [Link]()
print(current_time)
Modules Python Random
datetime is just the beginning. There are hundreds of Python modules that
you can use. Another one of the most commonly used is random which
allows you to generate numbers or select items at random.
With random, we’ll be using more than one piece of the module’s
functionality, so the import syntax will look like:
import random
We’ll work with two common random functions:
[Link]() which takes a list as an argument and returns a
number from the list
[Link]() which takes two numbers as arguments and
generates a random number between the two numbers you passed in
Let’s take randomness to a whole new level by picking a random number
from a list of randomly generated numbers between 1 and 100.
Instructions
[Link] [Link] import the random library.
[Link] a variable random_list and set it equal to an empty list
[Link] the empty list into a list comprehension that
uses [Link]() to generate a random integer between 1 and 100
(inclusive) for each number in range(101).
[Link] a new variable randomer_number and set it equal
to [Link]() with random_list as an argument.
[Link] randomer_number out to see what number was picked!
import random
random_list = [[Link](1,101) for i in range(101)]
randomer_number = [Link](random_list)
print(randomer_number)
Modules Python Namespaces
Notice that when we want to invoke the randint() function we
call [Link](). This is default behavior where Python offers
a namespace for the module. A namespace isolates the functions, classes,
and variables defined in the module from the code in the file doing the
importing. Your local namespace, meanwhile, is where your code is run.
Python defaults to naming the namespace after the module being
imported, but sometimes this name could be ambiguous or lengthy.
Sometimes, the module’s name could also conflict with an object you have
defined within your local namespace.
Fortunately, this name can be altered by aliasing using the as keyword:
import module_name as name_you_pick_for_the_module
Aliasing is most often done if the name of the library is long and typing the
full name every time you want to use one of its functions is laborious.
You might also occasionally encounter import *. The * is known as a
“wildcard” and matches anything and everything. This syntax is considered
dangerous because it could pollute our local namespace. Pollution occurs
when the same name could apply to two possible things. For example, if
you happen to have a function floor() focused on floor tiles, using from
math import * would also import a function floor() that rounds down floats.
Let’s combine your knowledge of the random library with another fun
library called matplotlib, which allows you to plot your Python code in 2D.
You’ll use a new random function [Link]() that takes a range and a
number as its arguments. It will return the specified number of random
numbers from that range.
Instructions
[Link] import codecademylib3_seaborn, import pyplot from the
module matplotlib with the alias plt.
[Link] random below the other import statements. It’s best to keep all
imports at the top of your file.
[Link] a variable numbers_a and set it equal to the range of numbers 1
through 12 (inclusive).
[Link] a variable numbers_b and set it equal to a random sample of
twelve numbers within range(1000).
[Link] let’s plot these number sets against each other using plt.
Call [Link]() with your two variables as its arguments.
[Link] call [Link]() and run your code!
You should see a graph of random numbers displayed. You’ve used two
Python modules to accomplish this (random and matplotlib).
import codecademylib3_seaborn
from matplotlib import pyplot as plt
import random
numbers_a = range(1, 13)
numbers_b = [Link](range(1000), 12)
[Link](numbers_a, numbers_b)
[Link]()
Modules Python Decimals
Let’s say you are writing software that handles monetary transactions. If you
used Python’s built-in floating-point arithmetic to calculate a sum, it would
result in a weirdly formatted number.
cost_of_gum = 0.10
cost_of_gumdrop = 0.35
cost_of_transaction = cost_of_gum + cost_of_gumdrop
# Returns 0.44999999999999996
Being familiar with rounding errors in floating-point arithmetic you want to
use a data type that performs decimal arithmetic more accurately. You
could do the following:
from decimal import Decimal
cost_of_gum = Decimal('0.10')
cost_of_gumdrop = Decimal('0.35')
cost_of_transaction = cost_of_gum + cost_of_gumdrop
# Returns 0.45 instead of 0.44999999999999996
Above, we use the decimal module’s Decimal data type to add 0.10 with
0.35. Since we used the Decimal type the arithmetic acts much more as
expected.
Usually, modules will provide functions or data types that we can then use
to solve a general problem, allowing us more time to focus on the software
that we are building to solve a more specific problem.
Ready, set, fix some floating point math by using decimals!
Instructions
[Link] your code to see the weird floating point math that occurs.
[Link] [Link] import Decimal from the decimal module.
[Link] Decimal to make two_decimal_points only have two decimals points
and four_decimal_points to only have four decimal points.
from decimal import Decimal
two_decimal_points = Decimal('0.2') + Decimal('0.69')
print(two_decimal_points)
four_decimal_points = Decimal('0.53') * Decimal('0.65')
print(four_decimal_points)
Modules Python Files and Scope
You may remember the concept of scope from when you were learning
about functions in Python. If a variable is defined inside of a function, it will
not be accessible outside of the function.
Scope also applies to classes and to the files you are working within.
Files have scope? You may be wondering.
Yes. Even files inside the same directory do not have access to each other’s
variables, functions, classes, or any other code. So if I have a
file [Link] and another file hungry_people.py, how do I give my
hungry people access to all the sandwiches I defined?
Well, files are actually modules, so you can give a file access to another file’s
content using that glorious import statement.
With a single line of from sandwiches import sandwiches at the top
of hungry_people.py, the hungry people will have all the sandwiches they
could ever want.
Instructions
[Link] over to [Link] and define a function always_three() with no
parameters that returns 3.
[Link] your always_three() function in [Link]. Check out that error
message you get in the output terminal and the consequences of file scope.
[Link] the error with an import statement at the top of [Link] that
imports your function from library. Run your code and watch import do its
magic!
from library import always_three
always_three()
Dictionary
What is a Dictionary?
A dictionary is an unordered set of key: value pairs.
Suppose we want to store the prices of various items sold at a cafe:
Oatmeal is 3 dollars
Avocado Toast is 6 dollars
Carrot Juice is 5 dollars
Blueberry Muffin is 2 dollars
In Python, we can create a dictionary called menu to store this data:
menu = {"oatmeal": 3, "avocado toast": 6, "carrot juice": 5, "blueberry
muffin": 2}
Notice that:
1. A dictionary begins and ends with curly braces ({ and }).
2. Each item consists of a key (i.e., “oatmeal”) and a value (i.e., 3)
3. Each key: value pair (i.e., "oatmeal": 3 or "avocado toast": 6) is
separated by a comma (,)
4. It’s considered good practice to insert a space () after each comma,
but your code will still run without the space.
Dictionaries provide us with a way to map pieces of data to each other, so
that we can quickly find values that are associated with one another.
Instructions
[Link] have a dictionary of temperature sensors in your house and what
temperatures they read. You’ve just added a sensor to your "pantry", and it
reads 22 degrees. Add this pair to the dictionary on line 1.
[Link] the # in front of the definition of the dictionary num_cameras,
which represents the number of cameras in each area around your house. If
you run this code, you’ll get an error:
SyntaxError: invalid syntax
Try to find and fix the syntax error to make this code run.
sensors = {"living room": 21, "kitchen": 23, "bedroom": 20, "pantry":
22}
num_cameras = {"backyard": 6, "garage": 2, "driveway": 1}
print(sensors)
Make a Dictionary
In the previous exercise we saw a dictionary that maps strings to numbers
(i.e., "oatmeal": 3). However, the keys can be numbers as well. For example,
if we were mapping restaurant bill subtotals to the bill total after tip, a
dictionary could look like:
subtotal_to_total = {20: 24, 10: 12, 5: 6, 15: 18}
Values can be any type. You can use a string, a number, a list, or even
another dictionary as the value associated with a key!
For example:
students_in_classes = {"software design": ["Aaron", "Delila", "Samson"],
"cartography": ["Christopher", "Juan", "Marco"], "philosophy": ["Frederica",
"Manuel"]}
The list ["Aaron", "Delila", "Samson"], which is the value for the
key "software design", represents the students in that class.
You can also mix and match key and value types. For example:
person = {"name": "Shuri", "age": 18, "siblings": ["T'Chaka", "Ramonda"]}
Instructions
[Link] a dictionary called translations that maps the following words in
English to their definitions in Sindarin (the language of the elves):
English Sindarin
mountain orod
bread bass
friend mellon
horse roch
translations = {'mountain': 'orod',
'bread': 'bass',
'friend': 'mellon',
'horse': 'roch'
}
Invalid Keys
We can have a list or a dictionary as a value of an item in a dictionary, but
we cannot use these data types as keys of the dictionary. If we try to, we
will get a TypeError. For example:
powers = {[1, 2, 4, 8, 16]: 2, [1, 3, 9, 27, 81]: 3}
will yield:
TypeError: unhashable type: 'list'
The word “unhashable” in this context means that this ‘list’ is an object that
can be changed. Dictionaries in Python rely on each key having a hash
value, a specific identifier for the key. If the key can change, that hash value
would not be reliable. So the keys must always be unchangeable, hashable
data types, like numbers or strings.
Instructions
[Link] the code. You should get an error:
TypeError: unhashable type
Make the code run without errors by flipping the items in the dictionary so
that the strings are the keys and the lists are the values
children = {"von Trapp": ["Johannes", "Rosmarie", "Eleonore"],
"Corleone":["Sonny", "Fredo", "Michael"]}
Empty Dictionary
A dictionary doesn’t have to contain anything. You can create an empty
dictionary:
empty_dict = {}
We can create an empty dictionary when we plan to fill it later based on
some other input. We will explore ways to fill a dictionary in the next
exercise.
Instructions
[Link] an empty dictionary called my_empty_dictionary.
my_empty_dictionary = {}
Add A Key
To add a single key : value pair to a dictionary, we can use the syntax:
my_dict["new_key"] = "new_value"
For example, if we had our menu object from the first exercise:
menu = {"oatmeal": 3, "avocado toast": 6, "carrot juice": 5, "blueberry
muffin": 2}
and we wanted to add a new item, "cheesecake" for 8 dollars, we could use:
menu["cheesecake"] = 8
Now, menu looks like:
{"oatmeal": 3, "avocado toast": 6, "carrot juice": 5, "blueberry muffin": 2,
"cheesecake": 8}
Instructions
[Link] an empty dictionary called animals_in_zoo.
[Link] around the zoo, you see 8 zebras.
Add "zebras" to animals_in_zoo as a key with a value of 8.
[Link] primate house was bananas! Add "monkeys" to animals_in_zoo as a
key with a value of 12.
[Link] you leave the zoo, you are saddened that you did not see any
dinosaurs. Add "dinosaurs" to animals_in_zoo as a key with a value of 0.
[Link] animals_in_zoo.
animals_in_zoo = {}
animals_in_zoo['zebras'] = 8
animals_in_zoo['monkeys'] = 12
animals_in_zoo['dinosaurs'] = 0
print(animals_in_zoo)
Add Multiple Keys
If we wanted to add multiple key : value pairs to a dictionary at once, we
can use the .update() method.
Looking at our sensors object from the first exercise:
sensors = {"living room": 21, "kitchen": 23, "bedroom": 20}
If we wanted to add 3 new rooms, we could use:
[Link]({"pantry": 22, "guest room": 25, "patio": 34})
which would add all three items to the sensors dictionary.
Now, sensors looks like:
{"living room": 21, "kitchen": 23, "bedroom": 20, "pantry": 22, "guest room":
25, "patio": 34}
Instructions
[Link] one line of code, add two new users to the user_ids dictionary:
theLooper, with an id of 138475
stringQueen, with an id of 85739
[Link] user_ids.
user_ids = {"teraCoder": 9018293, "proProgrammer": 119238}
user_ids.update({'theLooper': 138475, 'stringQueen': 85739})
print(user_ids)
Overwrite Values
We know that we can add a key by using syntax like:
menu['avocado toast'] = 7
which will create a key 'avocado toast' and set the value to 7. But what if we
already have an 'avocado toast' entry in the menu dictionary?
In that case, our value assignment would overwrite the existing value
attached to the key 'avocado toast'.
menu = {"oatmeal": 3, "avocado toast": 6, "carrot juice": 5, "blueberry
muffin": 2}
menu["oatmeal"] = 5
print(menu)
would yield:
{"oatmeal": 5, "avocado toast": 6, "carrot juice": 5, "blueberry muffin": 2}
Notice the value of "oatmeal" has now changed to 5.
Instructions
[Link] the key "Supporting Actress" and set the value to "Viola Davis".
[Link] changing the definition of the dictionary oscar_winners, change
the value associated with the key "Best Picture" to "Moonlight".
oscar_winners = {"Best Picture": "La La Land", "Best Actor": "Casey
Affleck", "Best Actress": "Emma Stone", "Animated Feature":
"Zootopia"}
oscar_winners["Supporting Actress"] = "Viola Davis"
oscar_winners["Best Picture"] = "Moonlight"
List Comprehensions to Dictionaries
Let’s say we have two lists that we want to combine into a dictionary, like a
list of students and a list of their heights, in inches:
names = ['Jenny', 'Alexus', 'Sam', 'Grace']
heights = [61, 70, 67, 64]
Python allows you to create a dictionary using a list comprehension, with
this syntax:
students = {key:value for key, value in zip(names, heights)}
#students is now {'Jenny': 61, 'Alexus': 70, 'Sam': 67, 'Grace': 64}
Remember that zip() combines two lists into a list of pairs. This list
comprehension:
1. Takes a pair from the zipped list of pairs from names and heights
2. Names the elements in the pair key (the one originally from
the names list) and value (the one originally from the heights list)
3. Creates a key : value item in the students dictionary
4. Repeats steps 1-3 for the entire list of pairs
Instructions
[Link] have two lists, representing some drinks sold at a coffee shop and
the milligrams of caffeine in each. First, create a variable
called zipped_drinks that is a list of pairs between the drinks list and
the caffeine list.
[Link] a dictionary called drinks_to_caffeine by using a list
comprehension that goes through the zipped_drinks list and turns each pair
into a key:value item.
drinks = ["espresso", "chai", "decaf", "drip"]
caffeine = [64, 40, 0, 120]
zipped_drinks = zip(drinks, caffeine)
drinks_to_caffeine = {key: value for key, value in zipped_drinks}
Review
Instructions
[Link] are building a music streaming service. We have provided two lists,
representing songs in a user’s library and the amount of times each song
has been played.
Using a list comprehension, create a dictionary called plays that goes
through zip(songs, playcounts) and creates a song:playcount pair for
each song in songs and each playcount in playcounts.
[Link] plays.
[Link] printing plays, add a new entry to it. The entry should be for the
song "Purple Haze" and the playcount is 1.
[Link] user has caught Aretha Franklin fever and listened to “Respect” 5
more times. Update the value for "Respect" to be 94 in the plays dictionary.
[Link] a dictionary called library that has two key: value pairs:
key "The Best Songs" with a value of plays, the dictionary you
created
key "Sunday Feelings" with a value of an empty dictionary
[Link] library.
songs = ["Like a Rolling Stone", "Satisfaction", "Imagine", "What's
Going On", "Respect", "Good Vibrations"]
playcounts = [78, 29, 44, 21, 89, 5]
plays = {song:playcount for [song, playcount] in zip(songs,
playcounts)}
plays["Respect"] = 94
plays["Purple Haze"] = 1
library = {"The Best Songs": plays, "Sunday Feelings": {}}
print(library)
spread = {}
spread["past"] = [Link](13)
spread["present"] = [Link](22)
spread["future"] = [Link](10)
for key, value in [Link]():
print("Your "+key+" is the "+value+" card. ")
Get A Key
Once you have a dictionary, you can access the values in it by providing the
key. For example, let’s imagine we have a dictionary that maps buildings to
their heights, in meters:
building_heights = {"Burj Khalifa": 828, "Shanghai Tower": 632, "Abraj Al
Bait": 601, "Ping An": 599, "Lotte World Tower": 554.5, "One World Trade":
541.3}
Then we can access the data in it like this:
>>> building_heights["Burj Khalifa"]
828
>>> building_heights["Ping An"]
599
Instructions
[Link] have provided a dictionary that maps the elements of astrology to the
zodiac signs. Print out the list of zodiac signs associated with
the "earth" element.
[Link] out the list of the "fire" signs.
zodiac_elements = {"water": ["Cancer", "Scorpio", "Pisces"], "fire":
["Aries", "Leo", "Sagittarius"], "earth": ["Taurus", "Virgo",
"Capricorn"], "air":["Gemini", "Libra", "Aquarius"]}
print(zodiac_elements["earth"])
print(zodiac_elements["fire"])
Get an Invalid Key
Let’s say we have our dictionary of building heights from the last exercise:
building_heights = {"Burj Khalifa": 828, "Shanghai Tower": 632, "Abraj Al
Bait": 601, "Ping An": 599, "Lotte World Tower": 554.5, "One World Trade":
541.3}
What if we wanted to know the height of the Landmark 81 in Ho Chi Minh
City? We could try:
print(building_heights["Landmark 81"])
But "Landmark 81" does not exist as a key in
the building_heights dictionary! So this will throw a KeyError:
KeyError: 'Landmark 81'
One way to avoid this error is to first check if the key exists in the
dictionary:
key_to_check = "Landmark 81"
if key_to_check in building_heights:
print(building_heights["Landmark 81"])
This will not throw an error, because key_to_check in building_heights will
return False, and so we never try to access the key.
Instructions
[Link] the code. It should throw a KeyError! "energy" does not exist as one
of the elements.
[Link] the key "energy" to the zodiac_elements. It should map to a value
of "Not a Zodiac element". Run the code. Did this resolve the KeyError?
zodiac_elements = {"water": ["Cancer", "Scorpio", "Pisces"], "fire":
["Aries", "Leo", "Sagittarius"], "earth": ["Taurus", "Virgo",
"Capricorn"], "air":["Gemini", "Libra", "Aquarius"]}
zodiac_elements["energy"] = "Not a Zodiac element"
print(zodiac_elements["energy"])
Try/Except to Get a Key
We saw that we can avoid KeyErrors by checking if a key is in a dictionary
first. Another method we could use is a try/except:
key_to_check = "Landmark 81"
try:
print(building_heights[key_to_check])
except KeyError:
print("That key doesn't exist!")
When we try to access a key that doesn’t exist, the program will go into
the except block and print "That key doesn't exist!".
Instructions
[Link] a try block to try to print the caffeine level of "matcha". If there is
a KeyError, print "Unknown Caffeine Level".
[Link] the try block, add "matcha" to the dictionary with a value of 30.
caffeine_level = {"espresso": 64, "chai": 40, "decaf": 0, "drip": 120}
caffeine_level["matcha"] = 30
try:
print(caffeine_level["matcha"])
except KeyError:
print("Unknown Caffeine Level")
Safely Get a Key
We saw in the last exercise that we had to add a key:value pair to a
dictionary in order to avoid a KeyError. This solution is not sustainable. We
can’t predict every key a user may call and add all of those placeholder
values to our dictionary!
Dictionaries have a .get() method to search for a value instead of
the my_dict[key] notation we have been using. If the key you are trying
to .get() does not exist, it will return None by default:
building_heights = {"Burj Khalifa": 828, "Shanghai Tower": 632, "Abraj Al
Bait": 601, "Ping An": 599, "Lotte World Tower": 554.5, "One World Trade":
541.3}
#this line will return 632:
building_heights.get("Shanghai Tower")
#this line will return None:
building_heights.get("My House")
You can also specify a value to return if the key doesn’t exist. For example,
we might want to return a building height of 0 if our desired building is not
in the dictionary:
>>> building_heights.get('Shanghai Tower', 0)
632
>>> building_heights.get('Mt Olympus', 0)
0
>>> building_heights.get('Kilimanjaro', 'No Value')
'No Value'
Instructions
[Link] .get() to get the value of "teraCoder"‘s user ID, with 100000 as a
default value if the user doesn’t exist. Store it in a variable called tc_id.
Print tc_id to the console.
[Link] .get() to get the value of "superStackSmash"‘s user ID, with 100000 as
a default value if the user doesn’t exist. Store it in a variable called stack_id.
Print stack_id to the console.
user_ids = {"teraCoder": 100019, "pythonGuy": 182921,
"samTheJavaMaam": 123112, "lyleLoop": 102931, "keysmithKeith":
129384}
tc_id = user_ids.get("teraCoder", 100000)
stack_id = user_ids.get("superStackSmash", 100000)
print(tc_id)
print(stack_id)
Delete a Key
Sometimes we want to get a key and remove it from the dictionary.
Imagine we were running a raffle, and we have this dictionary mapping
ticket numbers to prizes:
raffle = {223842: "Teddy Bear", 872921: "Concert Tickets", 320291: "Gift
Basket", 412123: "Necklace", 298787: "Pasta Maker"}
When we get a ticket number, we want to return the prize and also remove
that pair from the dictionary, since the prize has been given away. We can
use .pop() to do this. Just like with .get(), we can provide a default value to
return if the key does not exist in the dictionary:
>>> [Link](320291, "No Prize")
"Gift Basket"
>>> raffle
{223842: "Teddy Bear", 872921: "Concert Tickets", 412123: "Necklace",
298787: "Pasta Maker"}
>>> [Link](100000, "No Prize")
"No Prize"
>>> raffle
{223842: "Teddy Bear", 872921: "Concert Tickets", 412123: "Necklace",
298787: "Pasta Maker"}
>>> [Link](872921, "No Prize")
"Concert Tickets"
>>> raffle
{223842: "Teddy Bear", 412123: "Necklace", 298787: "Pasta Maker"}
.pop() works to delete items from a dictionary, when you know the key
value.
Instructions
[Link] are designing the video game Big Rock Adventure. We have provided
a dictionary of items in the player’s inventory to add points to their health
meter. In one line, add the value of "stamina grains" to health_points and
remove the item from the dictionary. If the key does not exist, add 0
to health_points.
[Link] one line, add the value of "power stew" to health_points and remove
the item from the dictionary. If the key does not exist, add 0
to health_points.
[Link] one line, add the value of "mystic bread" to health_points and remove
the item from the dictionary. If the key does not exist, add 0
to health_points.
[Link] available_items and health_points.
available_items = {"health potion": 10, "cake of the cure": 5, "green
elixir": 20, "strength sandwich": 25, "stamina grains": 15, "power
stew": 30}
health_points = 20
health_points += available_items.pop("stamina grains", 0)
health_points += available_items.pop("power stew", 0)
health_points += available_items.pop("mystic bread", 0)
print(available_items)
print(health_points)
Get All Keys
Sometimes we want to operate on all of the keys in a dictionary. For
example, if we have a dictionary of students in a math class and their
grades:
test_scores = {"Grace":[80, 72, 90], "Jeffrey":[88, 68, 81], "Sylvia":[80, 82, 84],
"Pedro":[98, 96, 95], "Martin":[78, 80, 78], "Dina":[64, 60, 75]}
We want to get a roster of the students in the class, without including their
grades. We can do this with the built-in list() function:
>>> list(test_scores)
["Grace", "Jeffrey", "Sylvia", "Pedro", "Martin", "Dina"]
Dictionaries also have a .keys() method that returns a dict_keys object.
A dict_keys object is a view object, which provides a look at the current
state of the dicitonary, without the user being able to modify anything.
The dict_keys object returned by .keys() is a set of the keys in the dictionary.
You cannot add or remove elements from a dict_keys object, but it can be
used in the place of a list for iteration:
for student in test_scores.keys():
print(student)
will yield:
"Grace"
"Jeffrey"
"Sylvia"
"Pedro"
"Martin"
"Dina"
Instructions
[Link] a variable called users and assign it to be all of the keys of
the user_ids list.
[Link] a variable called lessons and assign it to be all of the keys of
the num_exercises list.
[Link] users to the console.
[Link] lessons to the console.
user_ids = {"teraCoder": 100019, "pythonGuy": 182921,
"samTheJavaMaam": 123112, "lyleLoop": 102931, "keysmithKeith":
129384}
num_exercises = {"functions": 10, "syntax": 13, "control flow": 15,
"loops": 22, "lists": 19, "classes": 18, "dictionaries": 18}
users = user_ids.keys()
lessons = num_exercises.keys()
print(users)
print(lessons)
Get All Values
Dictionaries have a .values() method that returns a dict_values object (just
like a dict_keys object but for values!) with all of the values in the dictionary.
It can be used in the place of a list for iteration:
test_scores = {"Grace":[80, 72, 90], "Jeffrey":[88, 68, 81], "Sylvia":[80, 82, 84],
"Pedro":[98, 96, 95], "Martin":[78, 80, 78], "Dina":[64, 60, 75]}
for score_list in test_scores.values():
print(score_list)
will yield:
[80, 72, 90]
[88, 68, 81]
[80, 82, 84]
[98, 96, 95]
[78, 80, 78]
[64, 60, 75]
There is no built-in function to get all of the values as a list, but if
you really want to, you can use:
list(test_scores.values())
However, for most purposes, the dict_list object will act the way you want a
list to act.
Instructions
[Link] a variable called total_exercises and set it equal to 0.
[Link] through the values in the num_exercises list and add each value to
the total_exercises variable.
[Link] the total_exercises variable to the console.
num_exercises = {"functions": 10, "syntax": 13, "control flow": 15,
"loops": 22, "lists": 19, "classes": 18, "dictionaries": 18}
total_exercises = 0
for exercises in num_exercises.values():
total_exercises += exercises
print(total_exercises)
Get All Items
You can get both the keys and the values with the .items() method.
Like .keys() and .values(), it returns a dict_list object. Each element of
the dict_list returned by .items() is a tuple consisting of:
(key, value)
so to iterate through, you can use this syntax:
biggest_brands = {"Apple": 184, "Google": 141.7, "Microsoft": 80, "Coca-
Cola": 69.7, "Amazon": 64.8}
for company, value in biggest_brands.items():
print(company + " has a value of " + str(value) + " billion dollars. ")
which would yield this output:
Apple has a value of 184 billion dollars.
Google has a value of 141.7 billion dollars.
Microsoft has a value of 80 billion dollars.
Coca-Cola has a value of 69.7 billion dollars.
Amazon has a value of 64.8 billion dollars.
Instructions
[Link] a for loop to iterate through the items of pct_women_in_occupation.
For each key : value pair, print out a string that looks like:
Women make up [value] percent of [key]s.
pct_women_in_occupation = {"CEO": 28, "Engineering Manager": 9,
"Pharmacist": 58, "Physician": 40, "Lawyer": 37, "Aerospace Engineer":
9}
for occupation, percentage in pct_women_in_occupation.items():
print("Women make up " + str(percentage) + " percent of " +
occupation + "s.")
Review
Instructions
[Link] have provided a pack of tarot cards, tarot. You are going to do a
three card spread of your past, present, and future.
Create an empty dictionary called spread.
[Link] first card you draw is card 13. Pop the value assigned to the
key 13 out of the tarot dictionary and assign it as the value of
the "past" key of spread.
[Link] second card you draw is card 22. Pop the value assigned to the
key 22 out of the tarot dictionary and assign it as the value of
the "present" key of spread.
[Link] third card you draw is card 10. Pop the value assigned to the
key 10 out of the tarot dictionary and assign it as the value of
the "future" key of spread.
[Link] through the items in the spread dictionary and for each key: value
pair, print out a string that says:
Your {key} is the {value} card.
[Link]! You have learned about how to modify and use
dictionaries.
tarot = { 1:"The Magician", 2: "The High Priestess", 3: "The
Empress", 4: "The Emperor", 5: "The Hierophant", 6: "The
Lovers", 7: "The Chariot", 8: "Strength", 9: "The Hermit", 10:
"Wheel of Fortune", 11: "Justice", 12: "The Hanged Man",
13: "Death", 14: "Temperance", 15: "The Devil", 16: "The
Tower", 17: "The Star", 18: "The Moon", 19: "The Sun", 20:
"Judgement", 21: "The World", 22: "The Fool"}
spread = {}
spread["past"] = [Link](13)
spread["present"] = [Link](22)
spread["future"] = [Link](10)
for key, value in [Link]():
print("Your "+key+" is the "+value+" card. ")
Scrabble
In this project, you will process some data from a group of friends playing
scrabble. You will use dictionaries to organize players, words, and points.
There are many ways you can extend this project on your own if you finish
and want to get more practice!
Tasks
Build your Point Dictionary
[Link] have provided you with two lists, letters and points. We would like to
combine these two into a dictionary that would map a letter to its point
value.
Using a list comprehension and zip, create a dictionary
called letter_to_points that has the elements of letters as the keys and the
elements of points as the values.
[Link] letters list did not take into account blank tiles. Add an element to
the letter_to_points dictionary that has a key of " " and a point value of 0.
Score a Word
[Link] want to create a function that will take in a word and return how
many points that word is worth.
Define a function called score_word that takes in a parameter word.
[Link] score_word, create a variable called point_total and set it to 0.
[Link] defining point_total, create a for loop that goes through the letters
in word and adds the point value of each letter to point_total.
You should get the point value from the letter_to_points dictionary. If the
letter you are checking for is not in letter_to_points, add 0 to
the point_total.
[Link] the for loop is finished, return point_total.
[Link]’s test this function! Create a variable called brownie_points and set it
equal to the value returned by the score_word() function with an input
of "BROWNIE".
[Link] expect the word BROWNIE to earn 15 points:
(B + R + O + W + N + I + E)
(3 + 1 + 1 + 4 + 4 + 1 + 1) = 15
Let’s print out brownie_points to make sure we got it right.
Score a Game
[Link] a dictionary called player_to_words that maps players to a list of
the words they have played. This table represents the data to transcribe
into your dictionary:
player1 wordNerd Lexi Con Prof Reader
BLUE EARTH ERASER ZAP
TENNIS EYES BELLY COMA
EXIT MACHINE HUSKY PERIOD
[Link] an empty dictionary called player_to_points.
[Link] through the items in player_to_words. Call each player player and
each list of words words.
Within your loop, create a variable called player_points and set it to 0.
[Link] the loop, create another loop that goes through
each word in words and adds the value of score_word() with word as an
input.
[Link] the inner loop ends, set the current player value to be a key
of player_to_points, with a value of player_points.
14.player_to_points should now contain the mapping of players to how
many points they’ve scored. Print this out to see the current standings for
this game!
If you’ve calculated correctly, wordNerd should be winning by 1 point.
[Link] you want extended practice, try to implement some of these ideas
with the Python you’ve learned:
play_word() — a function that would take in a player and a word, and
add that word to the list of words they’ve played
update_point_totals() — turn your nested loops into a function that
you can call any time a word is played
make your letter_to_points dictionary able to handle lowercase inputs
as well
letters = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
points = [1, 3, 3, 2, 1, 4, 2, 4, 1, 8, 5, 1, 3, 4, 1, 3, 10, 1, 1, 1, 1, 4, 4, 8, 4,
10]
letter_to_points = {
key: value
for key, value
in zip(letters, points)
letter_to_points[“ “] = 0
print(letter_to_points)
def score_word(word):
point_total = 0
for letter in word:
point_total +=
letter_to_points.get(letter, 0)
return point_total
brownie_points = score_word(“BROWNIE”)
print(brownie_points)
player_to_words = {
“player1”:[“BLUE”, “TENNIS”, “EXIT”],
“wordNerd”: [“EARTH”, “EYES”, “MACHINE”],
“Lexi Con”: [“ERASER”, “BELLY”, “HUSKY”],
“Prof Reader”: [“ZAP”, “COMA”, “PERIOD”]
player_to_points = {}
def update_point_totals():
for player, words in player_to_words.items():
player_points = 0
for word in words:
player_points += score_word(word)
player_to_points[player] = player_points
update_point_totals()
print(player_to_points)
def play_word(player, word):
player_to_words[player].append(word)
update_point_totals()
play_word(“player1”, “CODE”)
print(player_to_words)
print(player_to_points)
Sum Values
sum_values()
Instructions
[Link] a function named sum_values that takes a dictionary
named my_dictionary as a parameter. The function should return the sum
of the values of the dictionary
def sum_values(my_dictionary):
total = 0
for value in my_dictionary.values():
total += value
return total
print(sum_values({"milk":5, "eggs":2, "flour": 3}))
print(sum_values({10:1, 100:2, 1000:3}))
Even Keys
sum_even_keys()
Instructions
[Link] a function called sum_even_keys that takes a dictionary
named my_dictionary, with all integer keys and values, as a parameter. This
function should return the sum of the values of all even keys.
def sum_even_keys(my_dictionary):
total = 0
for key in my_dictionary.keys():
if key%2 == 0:
total += my_dictionary[key]
return total
print(sum_even_keys({1:5, 2:2, 3:3}))
print(sum_even_keys({10:1, 100:2, 1000:3}))
Add Ten
add_ten()
Instructions
[Link] a function named add_ten that takes a dictionary with integer
values named my_dictionary as a parameter. The function should add 10 to
every value in my_dictionary and return my_dictionary
def add_ten(my_dictionary):
for key in my_dictionary.keys():
my_dictionary[key] += 10
return my_dictionary
print(add_ten({1:5, 2:2, 3:3}))
print(add_ten({10:1, 100:2, 1000:3}))
Values That Are Keys
values_that_are_keys()
Instructions
[Link] a function named values_that_are_keys that takes a dictionary
named my_dictionary as a parameter. This function should return a list of all
values in the dictionary that are also keys.
def values_that_are_keys(my_dictionary):
value_keys = []
for value in my_dictionary.values():
if value in my_dictionary:
value_keys.append(value)
return value_keys
print(values_that_are_keys({1:100, 2:1, 3:4, 4:10}))
print(values_that_are_keys({"a":"apple", "b":"a", "c":100}))
Largest Value
max_key()
Instructions
[Link] a function named max_key that takes a dictionary
named my_dictionary as a parameter. The function should return the key
associated with the largest value in the dictionary.
def max_key(my_dictionary):
largest_key = float("-inf")
largest_value = float("-inf")
for key, value in my_dictionary.items():
if value > largest_value:
largest_value = value
largest_key = key
return largest_key
print(max_key({1:100, 2:1, 3:4, 4:10}))
print(max_key({"a":100, "b":10, "c":1000}))
Word Length Dict
word_length_dictionary()
Instructions
[Link] a function named word_length_dictionary that takes a list of strings
named words as a parameter. The function should return a dictionary of
key/value pairs where every key is a word in words and every value is the
length of that word.
def word_length_dictionary(words):
word_lengths = {}
for word in words:
word_lengths[word] = len(word)
return word_lengths
print(word_length_dictionary(["apple", "dog", "cat"]))
print(word_length_dictionary(["a", ""]))
Frequency Count
frequency_dictionary()
Instructions
[Link] a function named frequency_dictionary that takes a list of elements
named words as a parameter. The function should return a dictionary
containing the frequency of each element in words.
def frequency_dictionary(words):
freqs = {}
for word in words:
if word not in freqs:
freqs[word] = 0
freqs[word] += 1
return freqs
print(frequency_dictionary(["apple", "apple", "cat", 1]))
print(frequency_dictionary([0,0,0,0,0]))
Unique Values
unique_values()
Instructions
[Link] a function named unique_values that takes a dictionary
named my_dictionary as a parameter. The function should return the
number of unique values in the dictionary.
def unique_values(my_dictionary):
seen_values = []
for value in my_dictionary.values():
if value not in seen_values:
seen_values.append(value)
return len(seen_values)
print(unique_values({0:3, 1:1, 4:1, 5:3}))
print(unique_values({0:3, 1:3, 4:3, 5:3}))
Count First Letter
count_first_letter()
Instructions
[Link] a function named count_first_letter that takes a dictionary
named names as a parameter. names should be a dictionary where the key
is a last name and the value is a list of first names. For example, the
dictionary might look like this:
names = {"Stark": ["Ned", "Robb", "Sansa"], "Snow" : ["Jon"], "Lannister":
["Jaime", "Cersei", "Tywin"]}
The function should return a new dictionary where each key is the first
letter of a last name, and the value is the number of people whose last
name begins with that letter.
So in example above, the function would return:
{"S" : 4, "L": 3}
def count_first_letter(names):
letters = {}
for key in names:
first_letter = key[0]
if first_letter not in letters:
letters[first_letter] = 0
letters[first_letter] += len(names[key])
return letters
print(count_first_letter({"Stark": ["Ned", "Robb", "Sansa"], "Snow" :
["Jon"], "Lannister": ["Jaime", "Cersei", "Tywin"]}))
print(count_first_letter({"Stark": ["Ned", "Robb", "Sansa"], "Snow" :
["Jon"], "Sannister": ["Jaime", "Cersei", "Tywin"]}))
Reading a File
Computers use file systems to store and retrieve data. Each file is an
individual container of related information. If you’ve ever saved a
document, downloaded a song, or even sent an email you’ve created a file
on some computer somewhere. Even [Link], the Python program you’re
editing in the learning environment, is a file.
So, how do we interact with files using Python? We’re going to learn how to
read and write different kinds of files using code. Let’s say we had a file
called real_cool_document.txt with these contents:
real_cool_document.txt
Wowsers!
We could read that file like this:
[Link]
with open('real_cool_document.txt') as cool_doc:
cool_contents = cool_doc.read()
print(cool_contents)
This opens a file object called cool_doc and creates a new indented block
where you can read the contents of the opened file. We then read the
contents of the file cool_doc using cool_doc.read() and save the resulting
string into the variable cool_contents. Then we print cool_contents, which
outputs the statement Wowsers!.
Instructions
[Link] with to open the file [Link]. Save the file object as text_file.
[Link] the contents of text_file and save the results in text_data.
[Link] out text_data.
with open('[Link]') as text_file:
text_data = text_file.read()
print(text_data)
Iterating Through Lines
When we read a file, we might want to grab the whole document in a single
string, like .read() would return. But what if we wanted to store each line in
a variable? We can use the .readlines() function to read a text file line by
line instead of having the whole thing. Suppose we have a file:
keats_sonnet.txt
To one who has been long in city pent,
’Tis very sweet to look into the fair
And open face of heaven,—to breathe a prayer
Full in the smile of the blue firmament.
[Link]
with open('keats_sonnet.txt') as keats_sonnet:
for line in keats_sonnet.readlines():
print(line)
The above script creates a temporary file object called keats_sonnet that
points to the file keats_sonnet.txt. It then iterates over each line in the
document and prints the entire file [Link]
[Link] a with statement, create a file object pointing to the
file how_many_lines.txt. Store that file object in the variable lines_doc.
[Link] through each of the lines in lines_doc.readlines() using a for loop.
Inside the for loop print out each line of how_many_lines.txt.
with open('how_many_lines.txt') as lines_doc:
for line in lines_doc.readlines():
print(line)
Reading a Line
Sometimes you don’t want to iterate through a whole file. For that, there’s a
different file method, .readline(), which will only read a single line at a time.
If the entire document is read line by line in this way subsequent calls
to .readline() will not throw an error but will start returning an empty string
(""). Suppose we had this file:
millay_sonnet.txt
I shall forget you presently, my dear,
So make the most of this, your little day,
Your little month, your little half a year,
Ere I forget, or die, or move away,
[Link]
with open('millay_sonnet.txt') as sonnet_doc:
first_line = sonnet_doc.readline()
second_line = sonnet_doc.readline()
print(second_line)
This script also creates a file object called sonnet_doc that points to the
file millay_sonnet.txt. It then reads in the first line
using sonnet_doc.readline() and saves that to the variable first_line. It then
saves the second line (So make the most of this, your little day,) into the
variable second_line and then prints it out.
Instructions
[Link] a with statement, create a file object pointing to the
file just_the_first.txt. Store that file object in the variable first_line_doc.
[Link] the first line of just_the_first.txt into the variable first_line.
[Link] out the variable first_line.
with open('just_the_first.txt') as first_line_doc:
first_line = first_line_doc.readline()
print(first_line)
Writing a File
Reading a file is all well and good, but what if we want to create a file of our
own? With Python we can do just that. It turns out that our open() function
that we’re using to open a file to read needs another argument to open a
file to write to.
[Link]
with open('generated_file.txt', 'w') as gen_file:
gen_file.write("What an incredible file!")
Here we pass the argument 'w' to open() in order to indicate to open the
file in write-mode. The default argument is 'r' and
passing 'r' to open() opens the file in read-mode as we’ve been doing.
This code creates a new file in the same folder as [Link] and gives it the
text What an incredible file!. It’s important to note that if there is already a
file called generated_file.txt it will completely overwrite that file, erasing
whatever its contents were before.
Instructions
[Link] a file object for the file bad_bands.txt using the open() function
with the w argument. Assign this object to the temporary
variable bad_bands_doc.
[Link] the bad_bands_doc.write() method to add the name of a musical
group you dislike to the document bad_bands.
with open('bad_bands.txt', 'w') as bad_bands_doc:
bad_bands_doc.write('The Beatles')
Appending to a File
So maybe completely deleting and overwriting existing files is something
that bothers you. Isn’t there a way to just add a line to a file without
completely deleting it? Of course there is! Instead of opening the file using
the argument 'w' for write-mode, we open it with 'a' for append-mode. If
we have a generated file with the following contents:
generated_file.txt
This was a popular file...
Then we can add another line to that file with the following code:
[Link]
with open('generated_file.txt', 'a') as gen_file:
gen_file.write("... and it still is")
In the code above we open a file object in the temporary variable gen_file.
This variable points to the file generated_file.txt and, since it’s open in
append-mode, adds the line ... and it still is as a new line to the file. If you
were to open the file after running the script it would look like this:
generated_file.txt
This was a popular file...
... and it still is
Notice that opening the file in append-mode, with 'a' as an argument
to open(), means that using the file
object’s .write() method appends whatever is passed to the end of the file in
a new line. If we were to run [Link] again, this would be
what generated_file.txt looks like:
generated_file.txt
This was a popular file...
... and it still is
... and it still is
Notice that we’ve appended "... and it still is" to the file a second time! This
is because in [Link] we opened generated_file.txt in append-mode.
Instructions
[Link]’ve got a file, cool_dogs.txt, filled with all the cool dogs we know.
Somehow while compiling this list we forgot about one very cool dog. Let’s
fix that problem by adding him to our cool_dogs.txt.
Open up our file cool_dogs.txt in append-mode and assign it to the file
object cool_dogs_file.
[Link] your with block, add “Air Buddy” to cool_dogs.txt. Air Buddy is a
Golden Retriever that plays basketball, which more than qualifies him for
this list.
with open('cool_dogs.txt', 'a') as cool_dogs_file:
cool_dogs_file.write('Air Buddy')
What's With "with"?
We’ve been opening these files with this with block so far, but it seems a
little weird that we can only use our file variable in the indented block. Why
is that? The with keyword invokes something called a context manager for
the file that we’re calling open() on. This context manager takes care of
opening the file when we call open() and then closing the file after we leave
the indented block.
Why is closing the file so complicated? Well, most other aspects of our
code deal with things that Python itself controls. All the variables you
create: integers, lists, dictionaries — these are all Python objects, and
Python knows how to clean them up when it’s done with them. Since your
files exist outside your Python script, we need to tell Python when we’re
done with them so that it can close the connection to that file. Leaving a file
connection open unnecessarily can affect performance or impact other
programs on your computer that might be trying to access that file.
The with syntax replaces older ways to access files where you need to
call .close() on the file object manually. We can still open up a file and
append to it with the old syntax, as long as we remember to close the file
connection afterwards.
fun_cities_file = open('fun_cities.txt', 'a')
# We can now append a line to "fun_cities".
fun_cities_file.write("Montréal")
# But we need to remember to close the file
fun_cities_file.close()
In the above script we added “Montréal” as a new line in our
file fun_cities.txt. However, since we used the older-style syntax, we had to
remember to close the file afterwards. Since this is necessarily more
verbose (requires at least one more line of code) without being any more
expressive, using with is preferred.
Instructions
[Link] [Link] there’s a file object that doesn’t get closed correctly. Let’s fix
it by changing the syntax!
Remove this line:
close_this_file = open('fun_file.txt')
And change it to use the with syntax from our previous exercises.
Remember to indent the rest of the body so that we don’t get
an IndentError.
with open('fun_file.txt') as close_this_file:
setup = close_this_file.readline()
punchline = close_this_file.readline()
print(setup)
What Is a CSV File?
Text files aren’t the only thing that Python can read, but they’re the only
thing that we don’t need any additional parsing library to understand. CSV
files are an example of a text file that impose a structure to their data. CSV
stands for Comma-Separated Values and CSV files are usually the way that
data from spreadsheet software (like Microsoft Excel or Google Sheets) is
exported into a portable format. A spreadsheet that looks like the following
Name Username Email
Roger Smith rsmith wigginsryan@[Link]
Michelle Beck mlbeck hcosta@[Link]
Ashley Barker a_bark_x a_bark_x@[Link]
Lynn Gonzales goodmanjames lynniegonz@[Link]
Jennifer Chase chasej jchase@[Link]
Charles Hoover choover choover89@[Link]
Adrian Evans adevans adevans98@[Link]
Susan Walter susan82 swilliams@[Link]
Stephanie King stephanieking sking@[Link]
Erika Miller jessica32 ejmiller79@[Link]
In a CSV file that same exact data would be rendered like this:
[Link]
Name,Username,Email
Roger Smith,rsmith,wigginsryan@[Link]
Michelle Beck,mlbeck,hcosta@[Link]
Ashley Barker,a_bark_x,a_bark_x@[Link]
Lynn Gonzales,goodmanjames,lynniegonz@[Link]
Jennifer Chase,chasej,jchase@[Link]
Charles Hoover,choover,choover89@[Link]
Adrian Evans,adevans,adevans98@[Link]
Susan Walter,susan82,swilliams@[Link]
Stephanie King,stephanieking,sking@[Link]
Erika Miller,jessica32,ejmiller79@[Link]
Notice that the first row of the CSV file doesn’t actually represent any data,
just the labels of the data that’s present in the rest of the file. The rest of
the rows of the file are the same as the rows in the spreadsheet software,
just instead of being separated into different cells they’re separated by…
well I suppose it’s fair to say they’re separated by commas.
Instructions
[Link] files are just plain text files!
Open [Link] using our standard with syntax, saving the file object in the
temporary variable log_csv_file.
[Link] out the contents of [Link] by calling .read() on the file. Notice
that it is parsed as a string.
with open('[Link]') as log_csv_file:
print(log_csv_file.read())
Reading a CSV File
Recall our CSV file from our last exercise:
[Link]
Name,Username,Email
Roger Smith,rsmith,wigginsryan@[Link]
Michelle Beck,mlbeck,hcosta@[Link]
Ashley Barker,a_bark_x,a_bark_x@[Link]
Lynn Gonzales,goodmanjames,lynniegonz@[Link]
Even though we can read these lines as text without a problem, there are
ways to access the data in a format better suited for programming
purposes. In Python we can convert that data into a dictionary using
the csv library’s DictReader object. Here’s how we’d create a list of the email
addresses of all of the users in the above table:
import csv
list_of_email_addresses = []
with open('[Link]', newline='') as users_csv:
user_reader = [Link](users_csv)
for row in user_reader:
list_of_email_addresses.append(row['Email'])
In the above code we first import our csv library, which gives us the tools to
parse our CSV file. We then create the empty
list list_of_email_addresses which we’ll later populate with the email
addresses from our CSV. Then we open the [Link] file with the
temporary variable users_csv.
We pass the additional keyword argument newline='' to the file
opening open() function so that we don’t accidentally mistake a line break
in one of our data fields as a new row in our CSV (read more about this
in the Python documentation).
After opening our new CSV file we use [Link](users_csv) which
converts the lines of our CSV file to Python dictionaries which we can use
access methods for. The keys of the dictionary are, by default, the entries in
the first line of our CSV file. Since our CSV’s first line calls the third field in
our CSV “Email“, we can use that as the key in each row of our DictReader.
When we iterate through the rows of our user_reader object, we access all
of the rows in our CSV as dictionaries (except for the first row, which we
used to label the keys of our dictionary). By accessing the 'Email' key of
each of these rows we can grab the email address in that row and append it
to our list_of_email_addresses.
Instructions
[Link] the csv module.
[Link] up the file cool_csv.csv in the temporary variable cool_csv_file.
[Link] [Link] read the contents of cool_csv_file into a new
variable called cool_csv_dict.
4.cool_csv.csv includes a cool fact about every person in the CSV.
For each row in cool_csv_dict print out that row’s "Cool Fact".
import csv
with open('cool_csv.csv') as cool_csv_file:
cool_csv_dict = [Link](cool_csv_file)
for row in cool_csv_dict:
print(row['Cool Fact'])
Reading Different Types of CSV Files
I need to level with you, I’ve been lying to you for the past two exercises.
Well, kind of. We’ve been acting like CSV files are Comma-Separated Values
files. It’s true that CSV stands for that, but it’s also true that other ways of
separating values are valid CSV files these days.
People used to call Tab-Separated Values files TSV files, but as other
separators grew in popularity everyone realized that creating a new .[a-
z]sv file format for every value-separating character used is not sustainable.
So we call all files with a list of different values a CSV file and then use
different delimiters (like a comma or tab) to indicate where the different
values start and stop.
Let’s say we had an address book. Since addresses usually use commas in
them, we’ll need to use a different delimiter for our information. Since none
of our data has semicolons (;) in them, we can use those.
[Link]
Name;Address;Telephone
Donna Smith;126 Orr Corner Suite 857\nEast Michael, LA 54411;906-918-
6560
Aaron Osborn;6965 Miller Station Suite 485\nNorth Michelle, KS
64364;815.039.3661x42816
Jennifer Barnett;8749 Alicia Vista Apt. 288\nLake Victoriaberg, TN
51094;397-796-4842x451
Joshua Bryan;20116 Stephanie Stravenue\nWhitneytown, IA 87358;
(380)074-6173
Andrea Jones;558 Melissa Keys Apt. 588\nNorth Teresahaven, WA
63411;+57(8)7795396386
Victor Williams;725 Gloria Views Suite 628\nEast Scott, IN
38095;768.708.3411x954
Notice the \n character, this is the escape sequence for a new line. The
possibility of a new line escaped by a \n character in our data is why we
pass the newline='' keyword argument to the open() function.
Also notice that many of these addresses have commas in them! This is
okay, we’ll still be able to read it. If we wanted to, say, print out all the
addresses in this CSV file we could do the following:
import csv
with open('[Link]', newline='') as addresses_csv:
address_reader = [Link](addresses_csv, delimiter=';')
for row in address_reader:
print(row['Address'])
Notice that when we call [Link] we pass in the delimiter parameter,
which is the string that’s used to delineate separate fields in the CSV. We
then iterate through the CSV and print out each of the addresses.
Instructions
[Link] the csv module.
[Link] up the file [Link] in the variable books_csv.
[Link] a DictReader instance that uses the @ symbol as a delimiter to
read books_csv. Save the result in a variable called books_reader.
[Link] a list called isbn_list, iterate through books_reader to get the ISBN
number of every book in the CSV file. Use the ['ISBN'] key for the dictionary
objects passed to it.
import csv
with open('[Link]') as books_csv:
books_reader = [Link](books_csv, delimiter='@')
isbn_list = [book['ISBN'] for book in books_reader]
Writing a CSV File
Naturally if we have the ability to read different CSV files we might want to
be able to programmatically create CSV files that save output and data that
someone could load into their spreadsheet software. Let’s say we have a
big list of data that we want to save into a CSV file. We could do the
following:
big_list = [{'name': 'Fredrick Stein', 'userid': 6712359021, 'is_admin': False},
{'name': 'Wiltmore Denis', 'userid': 2525942, 'is_admin': False}, {'name':
'Greely Plonk', 'userid': 15890235, 'is_admin': False}, {'name': 'Dendris Stulo',
'userid': 572189563, 'is_admin': True}]
import csv
with open('[Link]', 'w') as output_csv:
fields = ['name', 'userid', 'is_admin']
output_writer = [Link](output_csv, fieldnames=fields)
output_writer.writeheader()
for item in big_list:
output_writer.writerow(item)
In our code above we had a set of dictionaries with the same keys for each,
a prime candidate for a CSV. We import the csv library, and then open a
new CSV file in write-mode by passing the 'w' argument to
the open() function.
We then define the fields we’re going to be using into a variable
called fields. We then instantiate our CSV writer object and pass two
arguments. The first is output_csv, the file handler object. The second is our
list of fields fields which we pass to the keyword parameter fieldnames.
Now that we’ve instantiated our CSV file writer, we can start adding lines to
the file itself! First we want the headers, so we call .writeheader() on the
writer object. This writes all the fields passed to fieldnames as the first row
in our file. Then we iterate through our big_list of data.
Each item in big_list is a dictionary with each field in fields as the keys. We
call output_writer.writerow() with the item dictionaries which writes each
line to the CSV file.
Instructions
[Link] have a list in the workspace access_log which is a list of dictionaries
we want to write out to a CSV file.
Let’s start by importing the csv module.
[Link] up the file [Link] in the temporary variable logger_csv. Don’t
forget to open the file in write-mode.
[Link] a [Link] instance called log_writer. Pass logger_csv as the
first argument and then fields as a keyword argument to the
keyword fieldnames.
[Link] the header to log_writer using the .writeheader() method.
[Link] through the access_log list and add each element to the CSV
using log_writer.writerow().
access_log = [{'time': '08:39:37', 'limit': 844404, 'address':
'[Link]'}, {'time': '13:13:35', 'limit': 543871, 'address':
'[Link]'}, {'time': '19:40:45', 'limit': 3021, 'address':
'[Link]'}, {'time': '18:57:16', 'limit': 67031769, 'address':
'[Link]'}, {'time': '21:17:13', 'limit': 9083, 'address':
'[Link]'}, {'time': '23:34:17', 'limit': 65913, 'address':
'[Link]'}, {'time': '13:58:05', 'limit': 1541474, 'address':
'[Link]'}, {'time': '10:52:00', 'limit': 11465607, 'address':
'[Link]'}, {'time': '14:56:12', 'limit': 109, 'address':
'[Link]'}, {'time': '18:56:35', 'limit': 6207, 'address':
'[Link]'}]
fields = ['time', 'address', 'limit']
import csv
with open('[Link]', 'w') as logger_csv:
log_writer = [Link](logger_csv, fieldnames=fields)
log_writer.writeheader()
for line in access_log:
log_writer.writerow(line)
Reading a JSON File
CSV isn’t the only file format that Python has a built-in library for. We can
also use Python’s file tools to read and write JSON. JSON, an abbreviation
of JavaScript Object Notation, is a file format inspired by the programming
language JavaScript. The name, like CSV is a bit of a misnomer — some
JSON is not valid JavaScript (and plenty of JavaScript is not valid JSON).
JSON’s format is endearingly similar to Python dictionary syntax, and so
JSON files might be easy to read from a Python developer standpoint.
Nonetheless, Python comes with a json package that will help us parse
JSON files into actual Python dictionaries. Suppose we have a JSON file like
the following:
purchase_14781239.json
{
'user': 'ellen_greg',
'action': 'purchase',
'item_id': '14781239',
}
We would be able to read that in as a Python dictionary with the following
code:
json_reader.py
import json
with open('purchase_14781239.json') as purchase_json:
purchase_data = [Link](purchase_json)
print(purchase_data['user'])
# Prints 'ellen_greg'
First we import the json package. We opened the file using our
trusty open() command. Since we’re opening it in read-mode we just need
to pass the file name. We save the file in the temporary
variable purchase_json.
We continue by parsing purchase_json using [Link](), creating a Python
dictionary out of the file. Saving the results into purchase_data means we
can interact with it. We print out one of the values of the JSON file by
keying into the purchase_data object.
Instructions
[Link]’s read a JSON file! Start by importing the json module.
[Link] up the file [Link], saving the file object to the
variable message_json.
Open the file in read-mode, without passing any additional arguments
to open().
3.
Pass the JSON file object as an argument to [Link]() and save the
resulting Python dictionary as message.
[Link] out message['text'].
import json
with open('[Link]') as message_json:
message = [Link](message_json)
print(message['text'])
Writing a JSON File
Naturally we can use the json library to translate Python objects to JSON as
well. This is especially useful in instances where you’re using a Python
library to serve web pages, you would also be able to serve JSON. Let’s say
we had a Python dictionary we wanted to save as a JSON file:
turn_to_json = {
'eventId': 674189,
'dateTime': '2015-02-12T09:23:17.511Z',
'chocolate': 'Semi-sweet Dark',
'isTomatoAFruit': True
}
We’d be able to create a JSON file with that information by doing the
following:
import json
with open('[Link]', 'w') as json_file:
[Link](turn_to_json, json_file)
We import the json module, open up a write-mode file under the
variable json_file, and then use the [Link]() method to write to the
file. [Link]() takes two arguments: first the data object, then the file
object you want to save.
Instructions
[Link] your workspace we’ve put dictionary called data_payload. We want to
save this to a file called [Link].
Let’s start by importing the json library.
[Link] a new file object in the variable data_json. The filename should
be '[Link]' and the file should be opened in write-mode.
[Link] [Link]() with data_payload and data_json to convert our data to
JSON and then save it to the file [Link].
data_payload = [
{'interesting message': 'What is JSON? A web application\'s little pile
of secrets.',
'follow up': 'But enough talk!'}
import json
with open('[Link]', 'w') as data_json:
[Link](data_payload, data_json)
Hacking The Fender
The Fender, a notorious computer hacker and general villain of the people,
has compromised several top-secret passwords including your own. Your
mission, should you choose to accept it, is threefold. You must acquire
access to The Fender‘s systems, you must update his "[Link]" file to
scramble the secret data. The last thing you need to do is add the signature
of Slash Null, a different hacker whose nefarious deeds could be very
conveniently halted by The Fender if they viewed Slash Null as a threat.
Use your knowledge of working with Python files to retrieve, manipulate,
obscure, and create data in your quest for justice. Work with CSV files and
other text files in this exploration of the strength of Python file
programming.
If you get stuck during this project, check out the project walkthrough
video which can be found at the bottom of the page after the final step of
the project.
Tasks
Reading In The Passwords
[Link] you there? We’ve opened up a communications link to The Fender‘s
secret computer. We need you to write a program that will read in the
compromised usernames and passwords that are stored in a file
called "[Link]".
First import the CSV module, since we’ll be needing it to parse the data.
[Link] need to create a list of users whose passwords have been
compromised, create a new list and save it to the
variable compromised_users.
[Link] we’ll need you to open up the file itself. Store it in a file object
called password_file.
[Link] the password_file object holder to our CSV reader for parsing. Save
the parsed [Link] object as password_csv.
[Link] we’ll want to iterate through each of the lines in the CSV.
Create a for loop and save each row of the CSV into the temporary
variable password_row.
[Link] your for loop, print out password_row['Username']. This is the
username of the person whose password was compromised.
Run your code, do you see a list of usernames?
[Link] the print statement. We want to add each username to the list
of compromised_users. Use the list’s .append() method to add the
username to compromised_users instead of printing them.
[Link] out of your with block for "[Link]". We have all the data we
need from that file.
Start a new with block, opening a file called compromised_users.txt. Open
this file in write-mode, saving the file object as compromised_user_file.
[Link] the new context-managed block opened by the with statement
start a new for loop.
Iterate over each of your compromised_users.
[Link] the username of
each compromised_user in compromised_users to compromised_user_file.
[Link] out of that with block. You’re doing great so far! We’ve got the data
we need to employ as insurance against The Fender.
Notifying the Boss
[Link] boss needs to know that you were successful in retrieving that
compromised data. We’ll need to send him an encoded message over the
internet. Let’s use JSON to do that.
First we’ll need to import the json module.
[Link] a new JSON file in write-mode called boss_message.json. Save the
file object to the variable boss_message.
[Link] a Python dictionary object within your with statement that relays
a boss message. Call this boss_message_dict.
Give it a "recipient" key with a value "The Boss".
Also give it a "message" key with the value "Mission Success".
[Link] out boss_message_dict to boss_message using [Link]().
Scrambling the Password
[Link] that we’ve safely recovered the compromised users we’ll want to
remove the "[Link]" file completely.
Create a new with block and open "new_passwords.csv" in write-mode.
Save the file object to a variable called new_passwords_obj.
[Link] of the people, Slash Null, is who we want The Fender to think
was behind this attack. He has a signature, whenever he hacks someone he
adds this signature to one of the files he touches. Here is the signature:
_ _ ___ __ ____
/ )( \ / __) / \(_ _)
) \/ ( ( (_ \( O ) )(
\____/ \___/ \__/ (__)
_ _ __ ___ __ _ ____ ____
/ )( \ / _\ / __)( / )( __)( \
) __ (/ \( (__ ) ( ) _) ) D (
\_)(_/\_/\_/ \___)(__\_)(____)(____/
____ __ __ ____ _ _
___ / ___)( ) / _\ / ___)/ )( \
(___) \___ \/ (_/\/ \\___ \) __ (
(____/\____/\_/\_/(____/\_)(_/
__ _ _ _ __ __
( ( \/ )( \( ) ( )
/ /) \/ (/ (_/\/ (_/\
\_)__)\____/\____/\____/
Save that as a multiline string to the variable slash_null_sig.
[Link] slash_null_sig to new_passwords_obj. Now we have the file to
replace [Link] with!
[Link] an incredible success! We’ll take care of moving the new
passwords file over the old one in case you want to practice hacking The
Fender in the future.
CLASSES
Class
A class is a template for a data type. It describes the kinds of information
that class will hold and how a programmer will interact with that data.
Define a class using the class keyword. PEP 8 Style Guide for Python
Code recommends capitalizing the names of classes to make them easier to
identify.
class CoolClass:
pass
In the above example we created a class and named it CoolClass. We used
the pass keyword in Python to indicate that the body of the class was
intentionally left blank so we don’t cause an IndentationError. We’ll learn
about all the things we can put in the body of a class in the next few
exercises.
Instructions
[Link] an empty class called Facade. We’ll chip away at it soon!
class Facade:
pass
Instantiation
A class doesn’t accomplish anything simply by being defined. A class must
be instantiated. In other words, we must create an instance of the class, in
order to breathe life into the schematic.
Instantiating a class looks a lot like calling a function. We would be able to
create an instance of our defined CoolClass as follows:
cool_instance = CoolClass()
Above, we created an object by adding parentheses to the name of the
class. We then assigned that new instance to the variable cool_instance for
safe-keeping.
Instructions
[Link] [Link] we see our Facade class from last exercise. Make
a Facade instance and save it to the variable facade_1.
class Facade:
pass
facade_1 = Facade()
Object-Oriented Programming
A class instance is also called an object. The pattern of defining classes and
creating objects to represent the responsibilities of a program is known
as Object Oriented Programming or OOP.
Instantiation takes a class and turns it into an object, the type() function
does the opposite of that. When called with an object, it returns the class
that the object is an instance of.
print(type(cool_instance))
# prints "<class '__main__.CoolClass'>"
We then print out the type() of cool_instance and it shows us that this
object is of type __main__.CoolClass.
In Python __main__ means “this current file that we’re running” and so one
could read the output from type() to mean “the class CoolClass that was
defined here, in the script you’re currently running.”
Instructions
[Link] [Link] we see facade_1 from last exercise. Try
calling type() on facade_1 and saving it to the variable facade_1_type.
[Link] out facade_1_type.
class Facade:
pass
facade_1 = Facade()
facade_1_type = type(facade_1)
print(facade_1_type)
Class Variables
When we want the same data to be available to every instance of a class we
use a class variable. A class variable is a variable that’s the same for every
instance of the class.
You can define a class variable by including it in the indented part of your
class definition, and you can access all of an object’s class variables
with [Link] syntax.
class Musician:
title = "Rockstar"
drummer = Musician()
print([Link])
# prints "Rockstar"
Above we defined the class Musician, then instantiated drummer to be an
object of type Musician. We then printed out the drummer’s .title attribute,
which is a class variable that we defined as the string “Rockstar”.
If we defined another musician, like guitarist = Musician() they would have
the same .title attribute.
Instructions
[Link] are digitizing grades for Jan van Eyck High School and Conservatory.
At Jan van High, as the students call it, 65 is the minimum passing grade.
Create a Grade class with a class attribute minimum_passing equal to 65.
class Grade:
minimum_passing = 65
Methods
Methods are functions that are defined as part of a class. The first argument
in a method is always the object that is calling the method. Convention
recommends that we name this first argument self. Methods always have at
least this one argument.
We define methods similarly to functions, except that they are indented to
be part of the class.
class Dog():
dog_time_dilation = 7
def time_explanation(self):
print("Dogs experience {} years for every 1 human
year.".format(self.dog_time_dilation))
pipi_pitbull = Dog()
pipi_pitbull.time_explanation()
# Prints "Dogs experience 7 years for every 1 human year."
Above we created a Dog class with a time_explanation method that takes
one argument, self, which refers to the object calling the function. We
created a Dog named pipi_pitbull and called
the .time_explanation() method on our new object for Pipi.
Notice we didn’t pass any arguments when we called .time_explanation(),
but were able to refer to self in the function body. When you call a method
it automatically passes the object calling the method as the first argument.
Instructions
[Link] Jan van High, the students are constantly calling the school rules into
question. Create a Rules class so that we can explain the rules.
[Link] Rules a method washing_brushes that returns the string .
"Point bristles towards the basin while washing your brushes."
class Rules:
def washing_brushes(self):
return "Point bristles towards the basin while washing your
brushes."
Methods with Arguments
Methods can also take more arguments than just self:
class DistanceConverter:
kms_in_a_mile = 1.609
def how_many_kms(self, miles):
return miles * self.kms_in_a_mile
converter = DistanceConverter()
kms_in_5_miles = converter.how_many_kms(5)
print(kms_in_5_miles)
# prints "8.045"
Above we defined a DistanceConverter class, instantiated it, and used it to
convert 5 miles into kilometers. Notice again that even
though how_many_kms takes two arguments in its definition, we only
pass miles, because self is implicitly passed (and refers to the
object converter).
Instructions
[Link]’s March 14th (known in some places as Pi day) at Jan van High, and
you’re feeling awfully festive. You decide to create a program that
calculates the area of a circle.
Create a Circle class with class variable pi. Set pi to the approximation 3.14.
[Link] Circle an area method that takes two parameters: self and radius.
Return the area as given by this formula:
area = pi * radius ** 2
[Link] an instance of Circle. Save it into the variable circle.
[Link] go to measure several circles you happen to find around.
A medium pizza that is 12 inches across.
Your teaching table which is 36 inches across.
The Round Room auditorium, which is 11,460 inches across.
You save the areas of these three things
into pizza_area, teaching_table_area, and round_room_area.
Remember that the radius of a circle is half the diameter. We gave three
diameters here, so halve them before you calculate the given circle’s area.
class Circle:
pi = 3.14
def area(self, radius):
return [Link] * radius ** 2
circle = Circle()
pizza_area = [Link](12 / 2)
teaching_table_area = [Link](36 / 2)
round_room_area = [Link](11460 / 2)
Constructors
There are several methods that we can define in a Python class that have
special behavior. These methods are sometimes called “magic”, because
they behave differently from regular methods. Another popular term
is dunder methods, so-named because they have two underscores (double-
underscore abbreviated to “dunder”) on either side of them.
The first dunder method we’re going to use is the __init__ method (note the
two underscores before and after the word “init”). This method is used
to initialize a newly created object. It is called every time the class is
instantiated.
Methods that are used to prepare an object being instantiated are
called constructors. The word “constructor” is used to describe similar
features in other object-oriented programming languages but
programmers who refer to a constructor in Python are usually talking about
the __init__ method.
class Shouter:
def __init__(self):
print("HELLO?!")
shout1 = Shouter()
# prints "HELLO?!"
shout2 = Shouter()
# prints "HELLO?!"
Above we created a class called Shouter and every time we create an
instance of Shouter the program prints out a shout. Don’t worry, this
doesn’t hurt the computer at all.
Pay careful attention to the instantiation syntax we use. Shouter() looks a
lot like a function call, doesn’t it? If it’s a function, can we pass parameters
to it? We absolutely can, and those parameters will be received by
the __init__ method.
class Shouter:
def __init__(self, phrase):
# make sure phrase is a string
if type(phrase) == str:
# then shout it out
print([Link]())
shout1 = Shouter("shout")
# prints "SHOUT"
shout2 = Shouter("shout")
# prints "SHOUT"
shout3 = Shouter("let it all out")
# prints "LET IT ALL OUT"
Above we’ve updated our Shouter class to take the additional
parameter phrase. When we created each of our objects we passed an
argument to the constructor. The constructor takes the
argument phrase and, if it’s a string, prints out the all-caps version
of phrase.
Instructions
[Link] a constructor to our Circle class.
Since we seem more frequently to know the diameter of a circle, it should
take the argument diameter.
It doesn’t need to do anything yet, just write pass in the body of the
constructor.
[Link] have the constructor print out the message "New circle with
diameter: {diameter}" when a new circle is created.
Create a circle teaching_table with diameter 36.
class Circle:
pi = 3.14
def __init__(self, diameter):
print("New circle with diameter:
{diameter}".format(diameter=diameter))
teaching_table = Circle(36)
Instance Variables
We’ve learned so far that a class is a schematic for a data type and an
object is an instance of a class, but why is there such a strong need to
differentiate the two if each object can only have the methods and class
variables the class has? This is because each instance of a class can hold
different kinds of data.
The data held by an object is referred to as an instance variable. Instance
variables aren’t shared by all instances of a class — they are variables that
are specific to the object they are attached to.
Let’s say that we have the following class definition:
class FakeDict:
pass
We can instantiate two different objects from this
class, fake_dict1 and fake_dict2, and assign instance variables to these
objects using the same attribute notation that was used for accessing class
variables.
fake_dict1 = FakeDict()
fake_dict2 = FakeDict()
fake_dict1.fake_key = "This works!"
fake_dict2.fake_key = "This too!"
# Let's join the two strings together!
working_string = "{} {}".format(fake_dict1.fake_key, fake_dict2.fake_key)
print(working_string)
# prints "This works! This too!"
Instructions
[Link] [Link] we have defined a Store class. Create two objects from this
store class, named alternative_rocks and isabelles_ices.
[Link] them both instance attributes called store_name.
Set alternative_rocks‘s store_name to “Alternative Rocks”.
Set isabelles_ices‘s store_name to “Isabelle’s Ices”.
class Store:
pass
alternative_rocks = Store()
isabelles_ices = Store()
alternative_rocks.store_name = "Alternative Rocks"
isabelles_ices.store_name = "Isabelle's Ices"
Attribute Functions
Instance variables and class variables are both accessed similarly in Python.
This is no mistake, they are both considered attributes of an object. If we
attempt to access an attribute that is neither a class variable nor an instance
variable of the object Python will throw an AttributeError.
class NoCustomAttributes:
pass
attributeless = NoCustomAttributes()
try:
attributeless.fake_attribute
except AttributeError:
print("This text gets printed!")
# prints "This text gets printed!"
What if we aren’t sure if an object has an attribute or not? getattr() is a
Python function that works a lot like the usual dot-syntax
(i.e., object_name.attribute_name) but we can supply a third argument that
will be the default if the object does not have the given attribute. What if
we only really care whether the attribute exists? hasattr() will return True if
an object has a given attribute and False otherwise.
Calling those functions looks like this:
hasattr(attributeless, "fake_attribute")
# returns False
getattr(attributeless, "other_fake_attribute", 800)
# returns 800, the default value
Above we checked if the attributeless object has the
attribute fake_attribute. Since it does not, hasattr() returned False. After
that, we used getattr to attempt to retrieve other_fake_attribute.
Since other_fake_attribute isn’t a real attribute on attributeless, our call
to getattr() returned the supplied default value 800, instead of throwing
an AttributeError.
Instructions
[Link] [Link] we have a list of different data types, some strings, some lists,
and some dictionaries, all saved in the variable how_many_s.
For every element in the list, check if the element has the attribute count. If
so, count the number of times the string "s" appears in the element. Print
this number.
how_many_s = [{'s': False}, "sassafrass", 18, ["a", "c", "s", "d", "s"]]
for element in how_many_s:
if hasattr(element, "count"):
print([Link]("s"))
Self
Since we can already use dictionaries to store key-value pairs, using objects
for that purpose is not really useful. Instance variables are more powerful
when you can guarantee a rigidity to the data the object is holding.
This convenience is most apparent when the constructor creates the
instance variables, using the arguments passed in to it. If we were creating
a search engine, and we wanted to create classes for each separate entry
we could return. We’d do that like this:
class SearchEngineEntry:
def __init__(self, url):
[Link] = url
codecademy = SearchEngineEntry("[Link]")
wikipedia = SearchEngineEntry("[Link]")
print([Link])
# prints "[Link]"
print([Link])
# prints "[Link]"
Since the self keyword refers to the object and not the class being called,
we can define a secure method on the SearchEngineEntry class that returns
the secure link to an entry.
class SearchEngineEntry:
secure_prefix = "[Link]
def __init__(self, url):
[Link] = url
def secure(self):
return "{prefix}{site}".format(prefix=self.secure_prefix, site=[Link])
codecademy = SearchEngineEntry("[Link]")
print([Link]())
# prints "[Link]
print([Link]())
# prints "[Link]
Above we define our secure() method to take just the one required
argument, self. We access both the class variable self.secure_prefix and the
instance variable [Link] to return a secure URL.
This is the strength of writing object-oriented programs. We can write our
classes to structure the data that we need and write methods that will
interact with that data in a meaningful way.
Instructions
[Link] [Link] you’ll find our familiar friend, the Circle class.
Even though we usually know the diameter beforehand, what we need for
most calculations is the radius.
In Circle‘s constructor set the instance variable [Link] to equal half
the diameter that gets passed in.
[Link] three Circles with three different diameters.
A medium pizza, medium_pizza, that is 12 inches across.
Your teaching table, teaching_table, which is 36 inches across.
The Round Room auditorium, round_room, which is 11,460
inches across.
[Link] a new method circumference for your circle object that takes only
one argument, self, and returns the circumference of a circle with the given
radius by this formula:
circumference = 2 * pi * radius
4.
Print out the circumferences of medium_pizza, teaching_table,
and round_room.
class Circle:
pi = 3.14
def __init__(self, diameter):
print("Creating circle with diameter {d}".format(d=diameter))
[Link] = diameter / 2
def circumference(self):
return 2 * [Link] * [Link]
medium_pizza = Circle(12)
teaching_table = Circle(36)
round_room = Circle(11460)
print(medium_pizza.circumference())
print(teaching_table.circumference())
print(round_room.circumference())
Everything is an Object
Attributes can be added to user-defined objects after instantiation, so it’s
possible for an object to have some attributes that are not explicitly defined
in an object’s constructor. We can use the dir() function to investigate an
object’s attributes at runtime. dir() is short for directory and offers an
organized presentation of object attributes.
class FakeDict:
pass
fake_dict = FakeDict()
fake_dict.attribute = "Cool"
dir(fake_dict)
# Prints ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__', '__weakref__', 'attribute']
That’s certainly a lot more attributes than we defined! Python automatically
adds a number of attributes to all objects that get created. These internal
attributes are usually indicated by double-underscores. But sure
enough, attribute is in that list.
Do you remember being able to use type() on Python’s native data types?
This is because they are also objects in Python. Their classes
are int, float, str, list, and dict. These Python classes have special syntax for
their instantiation, 1, 1.0, "hello", [], and {} specifically. But these instances
are still full-blown objects to Python.
fun_list = [10, "string", {'abc': True}]
type(fun_list)
# Prints <class 'list'>
dir(fun_list)
# Prints ['__add__', '__class__', [...], 'append', 'clear', 'copy', 'count', 'extend',
'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
Above we define a new list. We check it’s type and see that’s an
instantiation of class list. We use dir() to explore its attributes, and it gives
us a large number of internal Python dunder attributes, but, afterward, we
get the usual list methods.
Instructions
[Link] dir() on the number 5. Print out the results.
[Link] a function called this_function_is_an_object. It can take any
parameters and return anything you’d like.
[Link] out the result of calling dir() on this_function_is_an_object.
Functions are objects too!
print(dir(5))
def this_function_is_an_object(num):
return "Cheese is {} times better than everything else".format(num)
print(dir(this_function_is_an_object))
String Representation
One of the first things we learn as programmers is how to print out
information that we need for debugging. Unfortunately, when we print out
an object we get a default representation that seems fairly useless.
class Employee():
def __init__(self, name):
[Link] = name
argus = Employee("Argus Filch")
print(argus)
# prints "<__main__.Employee object at 0x104e88390>"
This default string representation gives us some information, like where the
class is defined and our computer’s memory address where this object is
stored, but is usually not useful information to have when we are trying to
debug our code.
We learned about the dunder method __init__. Now, we will learn another
dunder method called __repr__. This is a method we can use to tell Python
what we want the string representation of the class to be. __repr__ can only
have one parameter, self, and must return a string.
In our Employee class above, we have an instance variable called name that
should be unique enough to be useful when we’re printing out an instance
of the Employee class.
class Employee():
def __init__(self, name):
[Link] = name
def __repr__(self):
return [Link]
argus = Employee("Argus Filch")
print(argus)
# prints "Argus Filch"
We implemented the __repr__ method and had it return the .name attribute
of the object. When we printed the object out it simply printed the .name of
the object! Cool!
Instructions
[Link] a __repr__ method to the Circle class that returns
Circle with radius {radius}
[Link] out medium_pizza, teaching_table, and round_room.
class Circle:
pi = 3.14
def __init__(self, diameter):
[Link] = diameter / 2
def area(self):
return [Link] * [Link] ** 2
def circumference(self):
return [Link] * 2 * [Link]
def __repr__(self):
return "Circle with radius {radius}".format(radius=[Link])
medium_pizza = Circle(12)
teaching_table = Circle(36)
round_room = Circle(11460)
print(medium_pizza)
print(teaching_table)
print(round_room)
Review
Instructions
[Link] a class Student this will be our data model at Jan van Eyck High
School and Conservatory.
[Link] a constructor for Student. Have the constructor take in two
parameters: a name and a year. Save those two as
attributes .name and .year.
[Link] three instances of the Student class:
Roger van der Weyden, year 10
Sandro Botticelli, year 12
Pieter Bruegel the Elder, year 8
Save them into the variables roger, sandro, and pieter.
[Link] a Grade class, with minimum_passing as an attribute set to 65.
[Link] Grade a constructor. Take in a parameter score and assign it
to [Link].
[Link] the body of the constructor for Student, declare [Link] as an
empty list.
[Link] an .add_grade() method to Student that takes a parameter, grade.
.add_grade() should verify that grade is of type Grade and if so, add it to
the Student‘s .grades.
If grade isn’t an instance of Grade then .add_grade() should do nothing.
[Link] a new Grade with a score of 100 and add it
to pieter‘s .grades attribute using .add_grade().
[Link] job! You’ve created two classes and defined their interactions. This
is object-oriented programming! From here you could:
Write a Grade method .is_passing() that returns whether
a Grade has a passing .score.
Write a Student method get_average() that returns the
student’s average score.
Add an instance variable to Student that is a dictionary
called .attendance, with dates as keys and booleans as values
that indicate whether the student attended school that day.
Write your own classes to do whatever logic you want!
class Student:
def __init__(self, name, year):
[Link] = name
[Link] = year
[Link] = []
def add_grade(self, grade):
if type(grade) is Grade:
[Link](grade)
class Grade:
minimum_passing = 65
def __init__(self, score):
[Link] = score
roger = Student("Roger van der Weyden", 10)
sandro = Student("Sandro Botticelli", 12)
pieter = Student("Pieter Bruegel the Elder", 8)
pieter.add_grade(Grade(100))
Inheritance
Classes are designed to allow for more code reuse, but what if we need a
class that looks a lot like a class we already have? If the bulk of a class’s
definition is useful, but we have a new use case that is distinct from how
the original class was used, we can inherit from the original class. Think of
inheritance as a remix — it sounds a lot like the original, but there’s
something… different about it.
class User:
is_admin = False
def __init__(self, username)
[Link] = username
class Admin(User):
is_admin = True
Above we defined User as our base class. We want to create a new class
that inherits from it, so we created the subclass Admin. In the above
example, Admin has the same constructor as User. Only the class
variable is_admin is set differently between the two.
Sometimes a base class is called a parent class. In these terms, the class
inheriting from it, the subclass, is also referred to as a child class.
Instructions
[Link] [Link] we’ve already defined the class Bin. Create a subclass
of Bin called RecyclingBin.
class Bin:
pass
class RecyclingBin(Bin):
pass
Exceptions
There’s one very important family of class definitions built in to the Python
language. An Exception is a class that inherits from Python’s Exception class.
We can validate this ourselves using the issubclass() function. issubclass() is
a Python built-in function that takes two
parameters. issubclass() returns True if the first argument is a subclass of
the second argument. It returns False if the first class is not a subclass of
the second. issubclass() raises a TypeError if either argument passed in is
not a class.
issubclass(ZeroDivisionError, Exception)
# Returns True
Above, we checked whether ZeroDivisionError, the exception raised when
attempting division by zero, is a subclass of Exception. It is,
so issubclass returns True.
Why is it beneficial for exceptions to inherit from one another? Let’s
consider an example where we create our own exceptions. What if we were
creating software that tracks our kitchen appliances? We would be able to
design a suite of exceptions for that need:
class KitchenException(Exception):
"""
Exception that gets thrown when a kitchen appliance isn't working
"""
class MicrowaveException(KitchenException):
"""
Exception for when the microwave stops working
"""
class RefrigeratorException(KitchenException):
"""
Exception for when the refrigerator stops working
"""
In this code, we define three exceptions. First, we define
a KitchenException that acts as the parent to our other, specific kitchen
appliance exceptions. KitchenException subclasses Exception, so it behaves
in the same way that regular Exceptions do. Afterward we
define MicrowaveException and RefrigeratorException as subclasses.
Since our exceptions are subclassed in this way, we can catch any
of KitchenException‘s subclasses by catching KitchenException. For
example:
def get_food_from_fridge():
if [Link] == False:
raise RefrigeratorException
else:
return food
def heat_food(food):
if [Link] == False:
raise MicrowaveException
else:
[Link](food)
return food
try:
food = get_food_from_fridge()
food = heat_food(food)
except KitchenException:
food = order_takeout()
In the above example, we attempt to retrieve food from the fridge and heat
it in the microwave. If
either RefrigeratorException or MicrowaveException is raised, we opt to
order takeout instead. We catch
both RefrigeratorException and MicrowaveException in our try/except block
because both are subclasses of KitchenException.
Explore Python’s exception hierarchy in the Python documentation!
Instructions
[Link] [Link] we’ve defined a CandleShop class for our new candle shop
that we’ve named Here’s a Hot Tip: Buy Drip Candles. We want to define our
own exceptions for when we run out of candles to sell.
Define your own exception called OutOfStock that inherits from
the Exception class.
[Link] CandleShop raise your OutOfStock exception
when [Link]() tries to buy a candle that’s out of stock.
class OutOfStock(Exception):
pass
class CandleShop:
name = "Here's a Hot Tip: Buy Drip Candles"
def __init__(self, stock):
[Link] = stock
def buy(self, color):
if [Link][color] < 1:
raise OutOfStock
[Link][color] = [Link][color] - 1
candle_shop = CandleShop({'blue': 6, 'red': 2, 'green': 0})
candle_shop.buy('blue')
Overriding Methods
Inheritance is a useful way of creating objects with different class variables,
but is that all it’s good for? What if one of the methods needs to be
implemented differently? In Python, all we have to do to override a method
definition is to offer a new definition for the method in our subclass.
An overridden method is one that has a different definition from its parent
class. What if User class didn’t have an is_admin flag but just checked if it
had permission for something based on a permissions dictionary? It could
look like this:
class User:
def __init__(self, username, permissions):
[Link] = username
[Link] = permissions
def has_permission_for(self, key):
if [Link](key):
return True
else:
return False
Above we defined a class User which takes a permissions parameter in its
constructor. Let’s assume permissions is a dict. User has a
method .has_permission_for() implemented, where it checks to see if a
given key is in its permissions dictionary. We could then define
our Admin user like this:
class Admin(User):
def has_permission_for(self, key):
return True
Here we define an Admin class that subclasses User. It has all methods,
attributes, and functionality that User has. However, if you
call has_permission_for on an instance of Admin, it won’t check
its permissions dictionary. Since this User is also an Admin, we just say they
have permission to see everything!
Instructions
[Link] [Link], we’ve defined two classes, Message and User. Create
an Admin class that subclasses the User class.
[Link] User‘s .edit_message() method in Admin so that an Admin can
edit any messages.
class Message:
def __init__(self, sender, recipient, text):
[Link] = sender
[Link] = recipient
[Link] = text
class User:
def __init__(self, username):
[Link] = username
def edit_message(self, message, new_text):
if [Link] == [Link]:
[Link] = new_text
class Admin(User):
def edit_message(self, message, new_text):
[Link] = new_text
Super()
Overriding methods is really useful in some cases but sometimes we want
to add some extra logic to the existing method. In order to do that we need
a way to call the method from the parent class. Python gives us a way to do
that using super().
super() gives us a proxy object. With this proxy object, we can invoke the
method of an object’s parent class (also called its superclass). We call the
required function as a method on super():
class Sink:
def __init__(self, basin, nozzle):
[Link] = basin
[Link] = nozzle
class KitchenSink(Sink):
def __init__(self, basin, nozzle, trash_compactor=None):
super().__init__(basin, nozzle)
if trash_compactor:
self.trash_compactor = trash_compactor
Above we defined two classes. First, we defined a Sink class with a
constructor that assigns a rinse basin and a sink nozzle to a Sink instance.
Afterwards, we defined a KitchenSink class that inherits
from Sink. KitchenSink‘s constructor takes an additional parameter,
a trash_compactor. KitchenSink then calls the constructor for Sink with
the basin and nozzle it received using the super() function, with this line of
code:
super().__init__(basin, nozzle)
This line says: “call the constructor (the function called __init__) of the class
that is this class’s parent class.” In the example given, KitchenSink‘s
constructor calls the constructor for Sink. In this way, we can override a
parent class’s method to add some new functionality (like adding
a trash_compactor to a sink), while still retaining the behavior of the
original constructor (like setting the basin and nozzle as instance variables).
Instructions
[Link]’re invited to a potluck this week and decide to make your own
special version of Potato Salad!
In [Link] you’ll find a class called PotatoSalad, make a subclass
of PotatoSalad called SpecialPotatoSalad.
[Link] special potato salad recipe is pretty similar to a regular potato salad,
so let’s start with making that.
Create a new constructor for SpecialPotatoSalad that just calls the parent
constructor for PotatoSalad. Make sure that SpecialPotatoSalad‘s
constructor takes the same arguments as PotatoSalad.
[Link] difference with your special potato salad is… you add raisins to it!
You can’t remember when you started doing this, but Dolores always hoots
about it at her potlucks and if that isn’t the nicest thing. You always use the
full package of raisins for every potato salad you make, and each package
has 40 raisins in it.
In your constructor for SpecialPotatoSalad, after making regular potato
salad, set [Link] = 40.
class PotatoSalad:
def __init__(self, potatoes, celery, onions):
[Link] = potatoes
[Link] = celery
[Link] = onions
class SpecialPotatoSalad(PotatoSalad):
def __init__(self, potatoes, celery, onions):
super().__init__(potatoes, celery, onions)
[Link] = 40
Interfaces
You may be wondering at this point why we would even want to have two
different classes with two differently implemented methods to use the
same method name. This style is especially useful when we have an object
for which it might not matter which class the object is an instance of.
Instead, we’re interested in whether that object can perform a given task.
If we have the following code:
class Chess:
def __init__(self):
[Link] = setup_board()
[Link] = add_chess_pieces()
def play(self):
print("Playing chess!")
class Checkers:
def __init__(self):
[Link] = setup_board()
[Link] = add_checkers_pieces()
def play(self):
print("Playing checkers!")
In the code above we define two classes, Chess and Checkers. In Chess we
define a constructor that sets up the board and pieces, and
a .play() method. Checkers also defines a .play() method. If we have
a play_game() function that takes an instance of Chess or Checkers, it could
call the .play() method without having to check which class the object is an
instance of.
def play_game(chess_or_checkers):
chess_or_checkers.play()
chess_game = Chess()
checkers_game = Checkers()
chess_game_2 = Chess()
for game in [chess_game, checkers_game, chess_game_2]:
play_game(game)
"""
Prints out the following:
Playing chess!
Playing checkers!
Playing chess!
In this code, we defined a play_game function that could take either
a Chess object or a Checkers object. We instantiate a few objects and then
call play_game on each.
When two classes have the same method names and attributes, we say they
implement the same interface. An interface in Python usually refers to the
names of the methods and the arguments they take. Other programming
languages have more rigid definitions of what an interface is, but it usually
hinges on the fact that different objects from different classes can perform
the same operation (even if it is implemented differently for each class).
Instructions
[Link] [Link] we’ve defined an InsurancePolicy class. Create a subclass
of InsurancePolicy called VehicleInsurance.
[Link] a different subclass of InsurancePolicy called HomeInsurance.
[Link] VehicleInsurance a .get_rate() method that takes self as a parameter.
Return .001 multiplied by the price of the vehicle.
[Link] HomeInsurance a .get_rate() method that takes self as a parameter.
Return .00005 multiplied by the price of the home.
class InsurancePolicy:
def __init__(self, price_of_item):
self.price_of_insured_item = price_of_item
class VehicleInsurance(InsurancePolicy):
def get_rate(self):
return self.price_of_insured_item * .001
class HomeInsurance(InsurancePolicy):
def get_rate(self):
return self.price_of_insured_item * .00005
Polymorphism
All this talk of interfaces demonstrates flexibility in programming. Flexibility
in programming is a broad philosophy, but what’s worth remembering is
that we want to implement forms that are familiar in our programs so that
usage is expected. For example, let’s think of the + operator. It’s easy to
think of it as a single function that “adds” whatever is on the left with
whatever is on the right, but it does many different things in different
contexts:
# For an int and an int, + returns an int
2 + 4 == 6
# For a float and a float, + returns a float
3.1 + 2.1 == 5.2
# For a string and a string, + returns a string
"Is this " + "addition?" == "Is this addition?"
# For a list and a list, + returns a list
[1, 2] + [3, 4] == [1, 2, 3, 4]
Look at all the different things that + does! The hope is that all of these
things are, for the arguments given to them, the intuitive result of adding
them together. Polymorphism is the term used to describe the same syntax
(like the + operator here, but it could be a method name) doing different
actions depending on the type of data.
Polymorphism is an abstract concept that covers a lot of ground, but
defining class hierarchies that all implement the same interface is a way of
introducing polymorphism to our code.
Instructions
[Link] [Link] a few different types of data are provided. Call len() on each
of them.
Is the same operation happening for each? How is it different? How is it
similar? Does using len() to refer to these different operations make sense?
a_list = [1, 18, 32, 12]
a_dict = {'value': True}
a_string = "Polymorphism is cool!"
len(a_list)
len(a_dict)
len(a_string)
Dunder Methods
One way that we can introduce polymorphism to our class definitions is by
using Python’s special dunder methods. We’ve explored a few already, the
constructor __init__ and the string representation method __repr__, but
that’s only scratching the tip of the iceberg.
Python gives us the power to define dunder methods that define a custom-
made class to look and behave like a Python builtin. What does that mean?
Say we had a class that has an addition method:
class Color:
def __init__(self, red, blue, green):
[Link] = red
[Link] = blue
[Link] = green
def __repr__(self):
return "Color with RGB = ({red}, {blue}, {green})".format(red=[Link],
blue=[Link], green=[Link])
def add(self, other):
"""
Adds two RGB colors together
Maximum value is 255
"""
new_red = min([Link] + [Link], 255)
new_blue = min([Link] + [Link], 255)
new_green = min([Link] + [Link], 255)
return Color(new_red, new_blue, new_green)
red = Color(255, 0, 0)
blue = Color(0, 255, 0)
magenta = [Link](blue)
print(magenta)
# Prints "Color with RGB = (255, 255, 0)"
In this code we defined a Color class that implements an addition function.
Unfortunately, [Link](blue) is a little verbose for something that we have
an intuitive symbol for (i.e., the + symbol). Well, Python offers the dunder
method __add__ for this very reason! If we rename the add() method above
to something that looks like this:
class Color:
def __add__(self, other):
"""
Adds two RGB colors together
Maximum value is 255
"""
new_red = min([Link] + [Link], 255)
new_blue = min([Link] + [Link], 255)
new_green = min([Link] + [Link], 255)
return Color(new_red, new_blue, new_green)
Then, if we create the colors:
red = Color(255, 0, 0)
blue = Color(0, 255, 0)
green = Color(0, 0, 255)
We can add them together using the + operator!
# Color with RGB: (255, 255, 0)
magenta = red + blue
# Color with RGB: (0, 255, 255)
cyan = blue + green
# Color with RGB: (255, 0, 255)
yellow = red + green
# Color with RGB: (255, 255, 255)
white = red + blue + green
Since we defined an __add__ method for our Color class, we were able to
add these objects together using the + operator.
Instructions
[Link] [Link] there are two classes defined, Atom and Molecule.
Give Atom a .__add__(self, other) method that returns a Molecule with the
two Atoms.
class Atom:
def __init__(self, label):
[Link] = label
def __add__(self, other):
return Molecule([self, other])
class Molecule:
def __init__(self, atoms):
if type(atoms) is list:
[Link] = atoms
sodium = Atom("Na")
chlorine = Atom("Cl")
salt = Molecule([sodium, chlorine])
# salt = sodium + chlorine
Dunder Methods II
Python offers a whole suite of magic methods a class can implement that
will allow us to use the same syntax as Python’s built-in data types. You can
write functionality that allows custom defined types to behave like lists:
class UserGroup:
def __init__(self, users, permissions):
self.user_list = users
[Link] = permissions
def __iter__(self):
return iter(self.user_list)
def __len__(self):
return len(self.user_list)
def __contains__(self, user):
return user in self.user_list
In our UserGroup class above we defined three methods:
__init__, our constructor, which sets a list of users to the instance
variable self.user_list and sets the group’s permissions when we create
a new UserGroup.
__iter__, the iterator, we use the iter() function to turn the
list self.user_list into an iterator so we can use for user in
user_group syntax. For more information on iterators, review Python’s
documentation of Iterator Types.
__len__, the length method, so when we call len(user_group) it will
return the length of the underlying self.user_list list.
__contains__, the check for containment, allows us to use user in
user_group syntax to check if a User exists in the user_list we have.
These methods allow UserGroup to act like a list using syntax Python
programmers will already be familiar with. If all you need is something to
act like a list you could absolutely have used a list, but if you want to
bundle some other information (like a group’s permissions, for instance)
having syntax that allows for list-like operations can be very powerful.
We would be able to use the following code to do this, for example:
class User:
def __init__(self, username):
[Link] = username
diana = User('diana')
frank = User('frank')
jenn = User('jenn')
can_edit = UserGroup([diana, frank], {'can_edit_page': True})
can_delete = UserGroup([diana, jenn], {'can_delete_posts': True})
print(len(can_edit))
# Prints 2
for user in can_edit:
print([Link])
# Prints "diana" and "frank"
if frank in can_delete:
print("Since when do we allow Frank to delete things? Does no one
remember when he accidentally deleted the site?")
Above we created a set of users and then added them to UserGroups with
specific permissions. Then we used Python built-in functions and syntax to
calculate the length of a UserGroup, to iterate through a UserGroup and to
check for a User‘s membership in a UserGroup.
Instructions
[Link] [Link] you’ll find the class LawFirm.
Give LawFirm a .__len__() method that will return the number of lawyers in
the law firm.
[Link] LawFirm a .__contains__() method that takes two
parameters: self and lawyer and checks to see if lawyer is in [Link].
class LawFirm:
def __init__(self, practice, lawyers):
[Link] = practice
[Link] = lawyers
def __len__(self):
return len([Link])
def __contains__(self, lawyer):
return lawyer in [Link]
d_and_p = LawFirm("Injury", ["Donelli", "Paderewski"])
Review
Instructions
[Link] a class SortedList that inherits from the built-in type list.
[Link] that lists have a .append() method that takes a two
arguments, self and value. We’re going to have SortedList perform a sort
after every .append().
Overwrite the append method, leave it blank for now with
the pass keyword.
[Link], we want our new .append() to actually add the item to the list.
Write the code that would get SortedList to behave like a normal list when
calling the .append() method.
[Link] you’ve appended the new value, sort the list.
[Link]! We subclassed a Python primitive and introduced new
behavior to it.
Some things to consider:
When a SortedList gets initialized with unsorted values (say if
you call SortedList([4, 1, 5])) those values don’t get sorted! How
would you change SortedList so that the list is sorted right
after the object gets created?
What other Python builtins have functionality “missing”? Could
you write a new dictionary that uses a fallback value when it
tries to retrieve an item and can’t?
class SortedList(list):
def append(self, value):
super().append(value)
[Link]()
Basta Fazoolin'
You’ve started position as the lead programmer for the family-style Italian
restaurant Basta Fazoolin’ with My Heart. The restaurant has been doing
fantastically and seen a lot of growth lately. You’ve been hired to keep
things organized.
If you get stuck during this project or would like to see an experienced
developer work through it, click “Get Help“ to see a project walkthrough
video.
Making the Menus
[Link] Basta Fazoolin’ with my Heart our motto is simple: when you’re here
with family, that’s great! We have four different menus: brunch, early-bird,
dinner, and kids.
Create a Menu class .
[Link] Menu a constructor with the five
parameters self, name, items, start_time, and end_time.
[Link]’s create our first menu: brunch. Brunch is served from 11am to 4pm.
The following items are sold during brunch:
{
'pancakes': 7.50, 'waffles': 9.00, 'burger': 11.00, 'home fries': 4.50, 'coffee':
1.50, 'espresso': 3.00, 'tea': 1.00, 'mimosa': 10.50, 'orange juice': 3.50
}
[Link]’s create our second menu item early_bird. Early-bird Dinners are
served from 3pm to 6pm. The following items are available during the
early-bird menu:
{
'salumeria plate': 8.00, 'salad and breadsticks (serves 2, no refills)': 14.00,
'pizza with quattro formaggi': 9.00, 'duck ragu': 17.50, 'mushroom ravioli
(vegan)': 13.50, 'coffee': 1.50, 'espresso': 3.00,
}
[Link]’s create our third menu, dinner. Dinner is served from 5pm to 11pm.
The following items are available for dinner:
{
'crostini with eggplant caponata': 13.00, 'ceaser salad': 16.00, 'pizza with
quattro formaggi': 11.00, 'duck ragu': 19.50, 'mushroom ravioli (vegan)':
13.50, 'coffee': 2.00, 'espresso': 3.00,
}
[Link] let’s create our last menu, kids. The kids menu is available from 11am
until 9pm. The following items are available on the kids menu.
{
'chicken nuggets': 6.50, 'fusilli with wild mushrooms': 12.00, 'apple juice':
3.00
}
[Link] our Menu class a string representation method that will tell you
the name of the menu. Also, indicate in this representation when the menu
is available.
[Link] out our string representation. If you call print(brunch) it should print
out something like the following:
brunch menu available from 11am to 4pm
[Link] Menu a method .calculate_bill() that has two parameters: self,
and purchased_items, a list of the names of purchased items.
Have calculate_bill return the total price of a purchase consisiting of all the
items in purchased_items.
[Link] out Menu.calculate_bill(). We have a breakfast order for one order
of pancakes, one order of home fries, and one coffee. Pass that
into brunch.calculate_bill() and print out the price.
[Link] about an early-bird purchase? Our last guests ordered the
salumeria plate and the vegan mushroom ravioli. Calculate the bill
with .caluclate_bill().
Creating the Franchises
[Link] Fazoolin’ with my Heart has seen tremendous success with the
family market, which is fantastic because when you’re at Basta Fazoolin’
with my Heart with family, that’s great!
We’ve decided to create more than one restaurant to offer our fantastic
menus, services, and ambience around the country.
First, let’s create a Franchise class.
[Link] the Franchise class a constructor. Take in an address, and assign it
to [Link]. Also take in a list of menus and assign it to [Link].
[Link]’s create our first two franchises! Our flagship store is located
at "1232 West End Road" and our new installment is located at "12 East
Mulberry Street". Pass in all four menus along with these addresses to
define flagship_store and new_installment.
[Link] our Franchises a string represenation so that we’ll be able to tell
them apart. If we print out a Franchise it should tell us the address of the
restaurant.
[Link]’s tell our customers what they can order!
Give Franchise an .available_menus() method that takes in a time parameter
and returns a list of the Menu objects that are available at that time.
[Link]’s test out our .available_menus() method! Call it with 12 noon as an
argument and print out the results.
[Link]’s do another test! If we call .available_menus() with 5pm as an
argument and print out the results.
Creating Businesses!
[Link] we’ve been so successful building out a branded chain of
restaurants, we’ve decided to diversify. We’re going to create a restaurant
that sells arepas!
First let’s define a Business class.
[Link] Business a constructor. A Business needs a name and a list
of franchises.
[Link]’s create our first Business. The name is "Basta Fazoolin' with my
Heart" and the two franchises are flagship_store and new_installment.
[Link] we create our new business, we’ll need a Franchise and before
our Franchise we’ll need a menu. The items for our Take a’ Arepa available
from 10am until 8pm are the following:
{
'arepa pabellon': 7.00, 'pernil arepa': 8.50, 'guayanes arepa': 8.00, 'jamon
arepa': 7.50
}
Save this to a variable called arepas_menu.
[Link] let’s create our first Take a’ Arepa franchise! Our new restaurant is
located at "189 Fitzgerald Avenue". Save the Franchise object to a variable
called arepas_place.
[Link] let’s make our new Business! The business is called "Take a' Arepa"!
[Link]! You created a system of classes that help structure your code
and perform all business requirements you need. Whenever we need a new
feature we’ll have the well-organized code required to make developing
and shipping it easy.
[Link] you are stuck on the project or would like to see an experienced
developer work through the project, watch the following project
walkthrough video!
Resenje u videu
FUNCTION ARGUMENTS
Parameters and Arguments
Python’s functions offer us a very expressive syntax. We’re going to look
into some of the finer details of how functions in Python work and some
techniques we can use to be more intuitive while writing and calling
functions.
First, let’s consider some definitions:
A parameter is a variable in the definition of a function.
An argument is the value being passed into a function call.
A function definition begins with def and contains the entire following
indented block.
And function calls are the places a function is invoked, with
parentheses, after its definition
Let’s see this in a block of code:
# The "def" keyword is the start of a function definition
def function_name(parameter1, parameter2):
# The placeholder variables used inside a function definition are called
parameters
print(parameter1)
return parameter2
# The outdent signals the end of the function definition
# "Arguments" are the values passed into a function call
argument1 = "argument 1"
argument2 = "argument 2"
# A function call uses the functions name with a pair of parentheses
# and can return a value
return_val = function_name(argument1, argument2)
In the above code we defined the function function_name that takes two
parameters, parameter1 and parameter2. We then create two variables with
the values "argument 1" and "argument 2" and proceed to
call function_name with the two arguments.
Some of this terminology can be used inconsistently between schools,
people, and businesses. Some people don’t differentiate between
“parameter” and “argument” when speaking. It’s useful here because we’re
going to be looking at a lot of behavior that looks very similar in a function
definition and a function call, but will be subtly different. But the distinction
is sometimes unnecessary, so don’t get too hung up if something is called a
“parameter” that should be an “argument” or vice versa.
Instructions
[Link] [Link] call the function play_record with the argument next_album.
What’s the name of the parameter that play_record takes?
from record_library import place_record, rotate_record, drop_needle
def play_record(album):
place_record(album)
rotate_record(album)
drop_needle(album)
next_album = "Blondie / Parallel Lines"
play_record(next_album)
None: It's Nothing!
How do you define a variable that you can’t assign a value to yet? You
use None.
None is a special value in Python. It is unique (there can’t be two
different Nones) and immutable (you can’t update None or assign new
attributes to it).
none_var = None
if none_var:
print("Hello!")
else:
print("Goodbye")
# Prints "Goodbye"
None is falsy, meaning that it evaluates to False in an if statement, which is
why the above code prints “Goodbye”. None is also unique, which means
that you can test if something is None using the is keyword.
# first we define session_id as None
session_id = None
if session_id is None:
print("session ID is None!")
# this prints out "session ID is None!"
# we can assign something to session_id
if active_session:
session_id = active_session.id
# but if there's no active_session, we don't send sensitive data
if session_id is not None:
send_sensitive_data(session_id)
Above we initialize our session_id to None, then set our session_id if there
is an active session. Since session_id could either be None we check
if session_id is None before sending our sensitive data.
Instructions
[Link] a new review using get_next_review(). Save the results into a variable
called review.
[Link] if there is a review by comparing it against None. If review contains
a value that isn’t None, submit it by calling the
function submit_review() with review as an argument.
from review_lib import get_next_review, submit_review
review = get_next_review()
if review is not None:
submit_review(review)
Default Return
What does a function return when it doesn’t return anything? This sounds
like a riddle, but there is a correct answer. A Python function that does not
have any explicit return statement will return None after completing. This
means that all functions in Python return something, whether it’s explicit or
not. For example:
def no_return():
print("You've hit the point of no return")
# notice no return statement
here_it_is = no_return()
print(here_it_is)
# Prints out "None"
Above we defined a function called no_return() and saved the result to a
variable here_it_is. When we print() the value of here_it_is we get None,
referring to Python’s None. It’s possible to make this syntax even more
explicit — a return statement without any value returns None also.
def fifty_percent_off(item):
# Check if [Link] exists
if hasattr(item, 'cost'):
return [Link] / 2
# If not, return None
return
sale_price = fifty_percent_off(product)
if sale_price is None:
print("This product is not for sale!")
Here we have implemented a function that returns the cost of a product
with “50% Off” (or “half price”). We check if the item passed to our function
has a cost attribute. If it exists, we return half the cost. If not, we
simply return, which returns None.
When we plug a product into this function, we can expect two possibilities:
the first is that the item has a cost and this function returns half of that. The
other is that item does not have a listed cost and so the function
returns None. We can put error handling in the rest of our code, if we
get None back from this function that means whatever we’re looking at
isn’t for sale!
Instructions
[Link] of everyday Python functions return None. What’s the return value of
a call to print()? Since print() is a function it must return something.
Create a variable called prints_return and set it equal to a print statement.
Make sure to give the print statement parentheses and give it an argument
(like “hi!”).
Now print out prints_return.
[Link] [Link] is a list called sort_this_list. Create a new variable
called list_sort_return and set it equal to sort_this_list.sort().
[Link] do you expect list_sort_return to contain?
Print out list_sort_return.
prints_return = print("What does this print function return?")
print(prints_return)
sort_this_list = [14, 631, 4, 51358, 50000000]
list_sort_return = sort_this_list.sort()
print(list_sort_return)
Default Arguments
Function arguments are required in Python. So a standard function
definition that defines two parameters requires two arguments passed into
the function.
# Function definition with two required parameters
def create_user(username, is_admin):
create_email(username)
set_permissions(is_admin)
# Function call with all two required arguments
user1 = create_user('johnny_thunder', True)
# Raises a "TypeError: Missing 1 required positional argument"
user2 = create_user('djohansen')
Above we defined our function, create_user, with two parameters. We first
called it with two arguments, but then tried calling it with only one
argument and got an error. What if we had sensible defaults for this
argument?
Not all function arguments in Python need to be required. If we give a
default argument to a Python function that argument won’t be required
when we call the function.
# Function defined with one required and one optional parameter
def create_user(username, is_admin=False):
create_email(username)
set_permissions(is_admin)
# Calling with two arguments uses the default value for is_admin
user2 = create_user('djohansen')
Above we defined create_user with a default argument for is_admin, so we
can call that function with only the one argument 'djohansen'. It assumes
the default value for is_admin: False. We can make both of our parameters
have a default value (therefore making them all optional).
# We can make all three parameters optional
def create_user(username=None, is_admin=False):
if username is None:
username = "Guest"
else:
create_email(username)
set_permissions(is_admin)
# So we can call with just one value
user3 = create_user('ssylvain')
# Or no value at all, which would create a Guest user
user4 = create_user()
Above we define the function with all optional parameters, if we call it with
one argument that gets interpreted as username. We can call it without any
arguments at all, which would only use the default values.
Instructions
[Link] [Link] there is a function called make_folders(). We want to add a
default argument to the nest parameter in make_folders().
Set is so that if we call make_folders() without an argument for nest the
function assumes it gets a value of False.
import os
def make_folders(folders_list, nest=False):
if nest:
"""
Nest all the folders, like
./Music/fun/parliament
"""
path_to_new_folder = ""
for folder in folders_list:
path_to_new_folder += "/{}".format(folder)
try:
[Link](path_to_new_folder)
except FileExistsError:
continue
else:
"""
Makes all different folders, like
./Music/ ./fun/ and ./parliament/
"""
for folder in folders_list:
try:
[Link](folder)
except FileExistsError:
continue
make_folders(['./Music', './fun', './parliament'])
Using Keyword and Positional Arguments
Not all of your arguments need to have default values. But Python will only
accept functions defined with their parameters in a specific order. The
required parameters need to occur before any parameters with a default
argument.
# Raises a TypeError
def create_user(is_admin=False, username, password):
create_email(username, password)
set_permissions(is_admin)
In the above code, we attempt to define a default argument
for is_admin without defining default arguments for the later
parameters: username and password.
If we want to give is_admin a default argument, we need to list it last in our
function definition:
# Works perfectly
def create_user(username, password, is_admin=False):
create_email(username, password)
set_permissions(is_admin)
Instructions
[Link] [Link] the function get_id tries to define a parameter with a default
argument before a required parameter.
Update the function signature of get_id so that website comes second
and html_id comes first.
import reqs as requests
from bs4 import BeautifulSoup
def get_id(html_id, website="[Link]
request = [Link](website)
parsed_html = BeautifulSoup([Link],
features="[Link]")
return parsed_html.find(id_=html_id)
Keyword Arguments
When we call a function in Python, we need to list the arguments to that
function to match the order of the parameters in the function definition.
We don’t necessarily need to do this if we pass keyword arguments.
We use keyword arguments by passing arguments to a function with a
special syntax that uses the names of the parameters. This is useful if the
function has many optional default arguments or if the order of a function’s
parameters is hard to tell. Here’s an example of a function with a lot of
optional arguments.
# Define a function with a bunch of default arguments
def log_message(logging_style="shout", message="", font="Times",
date=None):
if logging_style == 'shout':
# capitalize the message
message = [Link]()
print(message, date)
# Now call the function with keyword arguments
log_message(message="Hello from the past", date="November 20, 1693")
Above we defined log_message(), which can take from 0 to 4 arguments.
Since it’s not clear which order the four arguments might be defined in, we
can use the parameter names to call the function. Notice that in our
function call we use this syntax: message="Hello from the past". The key
word message here needs to be the name of the parameter we are trying
to pass the argument to.
Instructions
[Link] [Link] we’ve defined a draw_shape() function that will draw a shape
to the terminal! Call draw_shape() with "m" as
the character and line_breaks set to False.
import shapes
def draw_shape(shape_name="box", character="x", line_breaks=True):
shape = shapes.draw_shape(shape_name, character)
if not line_breaks:
print(shape[1:-1])
else:
print(shape)
draw_shape(character='m', line_breaks=False)
Don't Use Mutable Default Arguments
When writing a function with default arguments, it can be tempting to
include an empty list as a default argument to that function. Let’s say you
have a function called populate_list that has two required arguments, but
it’s easy to see that we might want to give it some default arguments in
case we don’t have either list_to_populate or length every time. So we’d
give it these defaults:
def populate_list(list_to_populate=[], length=1):
for num in range(length):
list_to_populate.append(num)
return list_to_populate
It’s reasonable to believe that list_to_populate will be given an empty list
every time it’s called. This isn’t the case! list_to_populate will be given a new
list once, in its definition, and all subsequent function calls will modify the
same list. This will happen:
returned_list = populate_list(length=4)
print(returned_list)
# Prints [0, 1, 2, 3] -- this is expected
returned_list = populate_list(length=6)
print(returned_list)
# Prints [0, 1, 2, 3, 0, 1, 2, 3, 4, 5] -- this is a surprise!
When we call populate_list a second time we’d expect the list [0, 1, 2, 3, 4,
5]. But the same list is used both times the function is called, causing some
side-effects from the first function call to creep into the second. This is
because a list is a mutable object.
A mutable object refers to various data structures in Python that are
intended to be mutated, or changed. A list has append and remove
operations that change the nature of a list. Sets and dictionaries are two
other mutable objects in Python.
It might be helpful to note some of the objects in Python that are not
mutable (and therefore OK to use as default arguments). int, float, and
other numbers can’t be mutated (arithmetic operations will return a new
number). tuples are a kind of immutable list. Strings are also immutable —
operations that update a string will all return a completely new string.
Instructions
[Link] [Link] we’ve written a helper function that adds a new menu item to
an order in a point-of-sale system. As you can see, we can start a new order
by calling update_order without an argument for current_order.
Unfortunately, there’s a bug in our code causing some previous order
contents to show up on other people’s bills!
First, try to guess what the output of this code will be. Then, run [Link].
We’ll fix this function in the next exercise, if you want more of an
explanation of what’s happening here, check out the hint!
def update_order(new_item, current_order=[]):
current_order.append(new_item)
return current_order
order1 = update_order({'item': 'burger', 'cost': '3.50'})
order1 = update_order({'item': 'soda', 'cost': '1.50'}, order1)
order2 = update_order({'item': 'soda', 'cost': '1.50'})
print(order2)
Using None as a Sentinel
So if we can’t use a list as a default argument for a function, what can we
use? If we want an empty list, we can use None as a special value to
indicate we did not receive anything. After we check whether an argument
was provided we can instantiate a new list if it wasn’t.
def add_author(authors_books, current_books=None):
if current_books is None:
current_books = []
current_books.extend(authors_books)
return current_books
In the above function, we accept current_books a value expected to be a
list. But we don’t require it. If someone calls add_author() without giving an
argument for current_books, we supply an empty list. This way multiple
calls to add_author won’t include data from previous calls to add_author.
Instructions
[Link] the function so that calls to update_order don’t have side-effects
— no order should affect other orders.
def update_order(new_item, current_order=None):
if current_order is None:
current_order = []
current_order.append(new_item)
return current_order
order1 = update_order({'item': 'burger', 'cost': '3.50'})
order1 = update_order({'item': 'soda', 'cost': '1.50'}, order1)
order2 = update_order({'item': 'soda', 'cost': '1.50'})
print(order2)
Unpacking Multiple Returns
A Python function can return multiple things. This is especially useful in
cases where bundling data into a different structure (a dictionary or a list,
for instance) would be excessive. In Python we can return multiple pieces of
data by separating each variable with a comma:
def multiple_returns(cool_num1, cool_num2):
sum_nums = cool_num1 + cool_num2
div_nums = cool_num1 / cool_num2
return sum_nums, div_nums
Above we created a function that returns two
results, sum_nums and div_nums. What happens when we call the function?
sum_and_div = multiple_returns(20, 10)
print(sum_and_div)
# Prints "(30, 2)"
print(sum_and_div[0])
# Prints "30"
So we get those two values back in what’s called a tuple, an immutable list-
like object indicated by parentheses. We can index into the tuple the same
way as a list and so sum_and_div[0] will give us our sum_nums value
and sum_and_div[1] will produce our div_nums value.
What if we wanted to save these two results in separate variables? Well we
can by unpacking the function return. We can list our new variables,
comma-separated, that correspond to the number of values returned:
sum, div = sum_and_div(18, 9)
print(sum)
# Prints "27"
print(div)
# Prints "2"
Above we were able to unpack the two values returned into separate
variables.
Instructions
[Link] [Link] you’ll find the definition of the
function scream_and_whisper(). Call the function with a string of your
choice and store the results in the_scream and the_whisper.
def scream_and_whisper(text):
scream = [Link]()
whisper = [Link]()
return scream, whisper
the_scream, the_whisper = scream_and_whisper("Hello There!")
Positional Argument Unpacking
We don’t always know how many arguments a function is going to receive,
and sometimes we want to handle any possibility that comes at us. Python
gives us two methods of unpacking arguments provided to functions. The
first method is called positional argument unpacking, because it unpacks
arguments given by position. Here’s what that looks like:
def shout_strings(*args):
for argument in args:
print([Link]())
shout_strings("hi", "what do we have here", "cool, thanks!")
# Prints out:
# "HI"
# "WHAT DO WE HAVE HERE"
# "COOL, THANKS!"
In shout_strings() we use a single asterisk (*) to indicate we’ll accept any
number of positional arguments passed to the function. Our
parameter args is a tuple of all of the arguments passed. In this
case args has three values inside, but it can have many more (or fewer).
Note that args is just a parameter name, and we aren’t limited to that name
(although it is rather standard practice). We can also have other positional
parameters before our *args parameter. We can’t, as we’ll see, :
def truncate_sentences(length, *sentences):
for sentence in sentences:
print(sentence[:length])
truncate_sentences(8, "What's going on here", "Looks like we've been cut
off")
# Prints out:
# "What's g"
# "Looks li"
Above we defined a function truncate_sentences that takes
a length parameter and also any number of sentences. The function prints
out the first length many characters of each sentence in sentences.
Instructions
[Link] Python library [Link] has a function called join(). join() takes an
arbitrary number of paths as arguments.
Use the join() function to join all three of the path segments, and print out
the results!
[Link] your own function, called myjoin() which takes an arbitrary number
of strings and appends them all together, similar to [Link]().
from [Link] import join
path_segment_1 = "/Home/User"
path_segment_2 = "Codecademy/videos"
path_segment_3 = "cat_videos/surprised_cat.mp4"
print(join(path_segment_1, path_segment_2, path_segment_3))
def myjoin(*args):
joined_string = args[0]
for arg in args[1:]:
joined_string += '/' + arg
return joined_string
print(myjoin(path_segment_1, path_segment_2, path_segment_3))
Keyword Argument Unpacking
Python doesn’t stop at allowing us to accept unlimited positional
parameters, it gives us the power to define functions with unlimited
keyword parameters too. The syntax is very similar, but uses two asterisks
(**) instead of one. Instead of args, we call this kwargs — as a shorthand for
keyword arguments.
def arbitrary_keyword_args(**kwargs):
print(type(kwargs))
print(kwargs)
# See if there's an "anything_goes" keyword arg
# and print it
print([Link]('anything_goes'))
arbitrary_keyword_args(this_arg="wowzers", anything_goes=101)
# Prints "<class 'dict'>
# Prints "{'this_arg': 'wowzers', 'anything_goes': 101}"
# Prints "101"
As you can see, **kwargs gives us a dictionary with all the keyword
arguments that were passed to arbitrary_keyword_args. We can access
these arguments using standard dictionary methods.
Since we’re not sure whether a keyword argument will exist, it’s probably
best to use the dictionary’s .get() method to safely retrieve the keyword
argument. Do you remember what .get() returns if the key is not in the
dictionary? It’s None!
Instructions
[Link] string .format() method can utilize keyword argument syntax if you
give placeholder names in curly braces in a string. For example:
"{place} is {adjective} this time of year.".format(place="New York",
adjective="quite cold, actually")
Format the string in [Link] within the print() statement. Give arguments
for the placeholders given.
2.create_products() takes a dictionary object and iterates over it, we can
change it so that it uses keyword arguments instead. Update this function
signature so products_dict contains all the keyword arguments passed
to create_products().
[Link] the call to create_products() to pass in each of those dictionary
items as a keyword argument instead.
# Checkpoint 1
print("My name is {name} and I'm feeling {feeling}.".format(
name="Tim",
feeling="10/10",
))
# Checkpoint 2
from products import create_product
# Update create_products() to take arbitrary keyword arguments
def create_products(**products_dict):
for name, price in products_dict.items():
create_product(name, price)
# Checkpoint 3
# Update the call to `create_products()` to pass in this dictionary as a
series of keyword
create_products(
Baseball='3',
Shirt='14',
Guitar='70')
Using Both Keyword and Positional Unpacking
This keyword argument unpacking syntax can be used even if the function
takes other parameters. However, the parameters must be listed in this
order:
All named positional parameters
An unpacked positional parameter (*args)
All named keyword parameters
An unpacked keyword parameter (**kwargs)
Here’s a function with all possible types of parameter:
def main(filename, *args, user_list=None, **kwargs):
if user_list is None:
user_list = []
if '-a' in args:
user_list = all_users()
if [Link]('active'):
user_list = [user for user_list if [Link]]
with open(filename) as user_file:
user_file.write(user_list)
Looking at the signature of main() we define four different kinds of
parameters. The first, filename is a normal required positional parameter.
The second, *args, is all positional arguments given to a function after that
organized as a tuple in the parameter args. The third, user_list, is a keyword
parameter with a default value. Lastly, **kwargs is all other keyword
arguments assembled as a dictionary in the parameter kwargs.
A possible call to the function could look like this:
main("files/users/[Link]",
"-d",
"-a",
save_all_records=True,
user_list=current_users)
In the body of main() these arguments would look like this:
filename == "files/users/[Link]"
args == ('-d', '-a)
user_list == current_users
kwargs == {'save_all_records': True}
We can use all four of these kinds of parameters to create functions that
handle a lot of possible arguments being passed to them.
Instructions
[Link] [Link] you’ll find the function remove() has three parameters: the
required positional filename, the arbitrary positional args, and the arbitrary
keyword kwargs.
Before returning the text, we want to remove all arguments passed as
positional arguments from the text. Using [Link]() change
every arg in args into an empty string "".
[Link] iterate over every kwarg and replacement in [Link]() (recall
this is how to iterate over key-value pairs in a dictionary).
Replace every instance of kwarg with replacement in text.
[Link] remove the bottom comment and see the text of Robin Hood; Being
A Complete History Of All The Notable And Merry Exploits Performed By Him
And His Men, On Many Occasions. by William Darton transformed!
def remove(filename, *args, **kwargs):
with open(filename) as file_obj:
text = file_obj.read()
for arg in args:
text = [Link](arg, "")
for kwarg, replacement in [Link]():
text = [Link](kwarg, replacement)
return text
print(remove("[Link]", "generous", "gallant", fond="amused by",
Robin="Mr. Robin"))
Passing Containers as Arguments
Not only can we accept arbitrarily many parameters to a function in our
definition, but Python also supports a syntax that makes deconstructing any
data that you have on hand to feed into a function that accepts these kinds
of unpacked arguments. The syntax is very similar, but is used when a
function is called, not when it’s defined.
def takes_many_args(*args):
print(','.join(args))
long_list_of_args = [145, "Mexico City", 10.9, "85C"]
# We can use the asterisk "*" to deconstruct the container.
# This makes it so that instead of a list, a series of four different
# positional arguments are passed to the function
takes_many_args(*long_list_of_args)
# Prints "145,Mexico City,10.9,85C"
We can use the * when calling the function that takes a series of positional
parameters to unwrap a list or a tuple. This makes it easy to provide a
sequence of arguments to a function even if that function doesn’t take a list
as an argument. Similarly we can use ** to destructure a dictionary.
def pour_from_sink(temperature="Warm", flow="Medium")
set_temperature(temperature)
set_flow(flow)
open_sink()
# Our function takes two keyword arguments
# If we make a dictionary with their parameter names...
sink_open_kwargs = {
'temperature': 'Hot',
'flow': "Slight",
}
# We can destructure them an pass to the function
pour_from_sink(**sink_open_kwargs)
# Equivalent to the following:
# pour_from_sink(temperature="Hot", flow="Slight")
So we can also use dictionaries and pass them into functions as keyword
arguments with that syntax. Notice that our pour_from_sink() function
doesn’t even accept arbitrary **kwargs. We can use this destructuring
syntax even when the function has a specific number of keyword or
positional arguments it accepts. We just need to be careful that the object
we’re destructuring matches the length (and names, if a dictionary) of the
signature of the function we’re passing it into.
Instructions
[Link]’ve got a latecomer to the new create_products syntax who wants to
still pass in a dictionary. Unpack new_product_dict while passing it
to create_products() as an argument.
from products import create_product
def create_products(**products_dict):
for name, price in products_dict.items():
create_product(name, price)
new_product_dict = {
'Apple': 1,
'Ice Cream': 3,
'Chocolate': 5,
# Call create_product() by passing new_product_dict
# as kwargs!
create_products(**new_product_dict)
The Nile
The Nile fullfilment agency brings everything you could possibly want
straight to your door! Use your knowledge of Python functions and how to
manipulate arguments to help automate practices for the biggest world-
changing company.
If you get stuck during this project, check out the project walkthrough
video which can be found at the bottom of the page after the final step of
the project.
Tasks
Not Just A River In Egypt
[Link] The Nile our biggest concern is our consumers, and our biggest cost is
delivering their goods to them. We want to develop a program that will
help us minimize these costs so we can continue making everyone happy.
First we’ll need to calculate these costs using a function that you’re going
to write called calculate_shipping_cost().
Give calculate_shipping_cost three parameters: from_coords, to_coords,
and shipping_type.
.
[Link] from_coords and to_coords are tuples, containing first the latitude
and then the longitude. Since our get_distance() function looks for all four
as separate arguments, we’ll need to separate these variables out.
Inside calculate_shipping_cost unpack those tuples
into from_lat, from_long, to_lat, and to_long.
[Link] call get_distance(from_lat, from_long, to_lat, to_long) and save the
result as distance.
There’s other ways to separate those two coordinates when calling this
function, how would you have done it?
[Link], get the shipping_rate by using the
provided SHIPPING_PRICES dictionary and fetching the key passed in
as shipping_type.
[Link] the price by multiplying the distance by the shipping_rate.
[Link], return the formatted price, created by calling the
provided format_price() on the price itself.
[Link] about our shoppers who hastily purchase goods without indicating
their shipping type? Let’s give our function a default argument
for shipping_type. Since they’re in such a hurry let’s make the default
argument 'Overnight'. They’ll be happier to get what they ordered earlier,
and we’ll be happier because they paid more money for it. It’s a win-win!
[Link] to make sure you wrote the function correctly? Try
calling test_function(calculate_shipping_cost) after your function definition.
Careers At The Nile
[Link] The Nile, we have a joke. Without our fantastic drivers, who fulfill
orders every day, we’d just be sitting with millions of toys, electronics, and
clothing in warehouses to ourselves.
Our team is important, and we want to make sure the hardest workers find
their home in our careers. In order to do that, we need to figure out who
the best person is for each job.
Write a function called calculate_driver_cost() with distance as the first
parmameter, and as many drivers as are available as positional arguments
after that, as drivers.
[Link] order to find the best person, we need to calculate how much it
would cost for any of the drivers to fulfill this order.
Create two new variables, cheapest_driver and cheapest_driver_price. Set
them both to None.
[Link] let’s iterate over every driver in drivers. Use a for loop.
[Link] calculate the driver_time for each driver by
multiplying [Link] by distance.
[Link] calculate the price_for_driver by
multiplying [Link] by driver_time.
[Link] we want to check if the current driver is the cheapest driver we’ve
looked at.
First, we’ll check if cheapest_driver is None, this likely means this is the first
driver we’ve looked at.
In that case, set cheapest_driver equal to driver and then
set cheapest_driver_price equal to price_for_driver.
[Link] an elif statment, check if price_for_driver is less
than cheapest_driver_price. This means that our current driver is cheaper
than the driver stored in cheapest_driver.
Update cheapest_driver to be equal to driver and
update cheapest_driver_price to be equal to price_for_driver.
[Link] outdenting out of our elif statement and the for loop,
return cheapest_driver_price and cheapest_driver.
The Nile Exclusive
[Link] first day, friend! Let’s try and figure out all the money you’ve
saved us today.
Let’s define a function called calculate_money_made().
This function will be passed a number of Trip IDs with corresponding trip
information as arguments, so let’s just take any keyword arguments passed
into it. Store them all as trips!
[Link]’s start a counter at 0. Create a variable called total_money_made that
will count up for us.
[Link] through every trip_id and trip in the trips dictionary.
[Link] the trip revenue into the variable trip_revenue by
calculating [Link] minus [Link].
[Link] up that sweet revenue by
incrementing total_money_made by trip_revenue.
[Link] your for loop, return the total!
[Link]! You’ve been a real life-saver around these parts. We
broke up functions using arbitrary and default parameters! Remember you
can test your function by
calling test_function(calculate_money_made) afterwards!
[Link] you are stuck on the project or would like to see an experienced
developer work through the project, watch the following project
walkthrough video!