CS111 Practice Quiz
This practice quiz is focused on memory and hashtables/dictionaries, helping to prepare you for the second quiz. Assume that all questions are worth the same amount.
Given these two dataclasses and the variations of a function to move a horse from one barn to another, answer the below questions.
@dataclass
class Horse:
name: str
size: float
barn: Barn
@dataclass
class Barn:
residents: list[Horse]
color: str
id: int
Question 1
def move_horse(my_horse: Horse, new_barn: Barn):
"""Takes in a horse and a new barn and moves the horse to the new barn"""
my_horse.barn.residents.remove(my_horse)
my_horse.barn = new_barn
new_barn.residents.append(my_horse)
def move_horse2(my_horse: Horse, new_barn: Barn):
"""Takes in a horse and a new barn and moves the horse to the new barn"""
my_horse.barn.residents.remove(my_horse)
my_horse = Horse(my_horse.name, my_horse.size, new_barn)
new_barn.residents.append(my_horse)
Now assume we ran the following code:
barn111 = Barn([], "red", 111)
barn180 = Barn([], "purple", 180)
gallant_fox = Horse("Gallant Fox", 232.7, barn111)
secretariat = Horse("Secretariat", 11.1, barn111)
barn111.residents.append(gallant_fox)
barn111.residents.append(secretariat)
How many Barn objects would be in memory after running this code?
Answer!
2
How many Horse objects would be in memory after running this code?
move_horse(gallant_fox, barn180)
move_horse2(secretariat, barn180)
Answer!
3 (don’t forget the one created in move_horse2!)
How many lists would be in memory after running this code?
Answer!
2
Assume that gallant_fox was placed in loc 1006 and that secretariat was placed in loc 1007.
After we run move_horse(gallant_fox, barn180)
(i.e. at memory point A), which of these horses are in a different memory location?
Answer!
Neither one! move_horse
changes barn assignments within memory, but doesn’t change the association between names and memory locations
After we run move_horse2(secretariat, barn180)
(i.e. at memory point B), which memory locations are listed in the residents list for barn180
?
Answer!
From the call to move_horse
, we know that gallant_fox’s memory location, loc 1006, is in this list. The second memory location in the list is NOT loc 1007, since it refers to the location for the new Horse that was created in move_horse2
. The original secretariat horse isn’t listed in any barn after this call.
Question 2
What if there were a huge number of horses in each barn? The residents
list for each barn might get really difficult to iterate through if we were looking for one particular horse! Let’s consider how to make a dictionary for each barn’s residents
instead.
Part A
Assume the value for the dictionary is a Horse
. What are some possible keys we could use for a dictionary of all the horses residing in any particular barn? What are the benefits or drawbacks of these?
Answer!
Since the Horse
dataclass has three fields, name
, size
, and barn
, let’s think about each of these as a possible key for our dictionary.
name
: Since each horse most likely has a unique name, this looks like a pretty good key. A name is also what we most likely identify a horse with: it makes sense that to get some information about gallant_fox
, we could look up my_dict["Gallant Fox"]
and get gallant_fox
.
size
: The size of a horse is represented by a float. We could easily imagine that two horses would be the same size, and then we could run into an issue! If we define my_dict[232.7] = gallant_fox
and then little secretariat
grows up to be of size 232.7 as well, we define my_dict[232.7] = secretariat
and then gallant_fox
is overwritten.
barn
: For a similar reason to size
, we can easily see that multiple horses living in one barn would overwrite each other. Also, in the context of this problem, this dictionary will serve as the information for a barn’s horses, so all of the horses in this dictionary will belong to the same barn and overwrite each other.
- Something else? Another option you might consider is to change the
Horse
dataclass to have some field that we know will be unique: for example, an “ID” field. This would allow for duplicate names, as well! Without changing our dataclass definition, however, the name might be the best choice for a key.
Part B
Let’s have our dictionary map names (strings) to Horses
for each barn, replacing the list of horses.
@dataclass
class Horse:
name: str
size: float
barn: Barn
@dataclass
class Barn:
residents: dict[str, Horse]
color: str
id: int
Complete the TODOs appropriately.
barn111 = Barn({}, "red", 111)
secretariat = Horse("Secretariat", 11.1, barn111)
Answer!
barn111.residents[secretariat.name] = secretariat
barn111.residents["Secretariat"].size = 232.7
Question 3
Say we have updated the Barn
dataclass’s residents field to take in a dictionary.
barn111 = Barn({}, "red", 111)
secretariat = Horse("Secretariat", 11.1, barn111)
whirlaway = Horse("Whirlaway", 777.0, barn111)
barn111.residents["Secretariat"] = secretariat
barn111.residents["Whirlaway"] = whirlaway
barn111.residents["Gallant Fox"] = Horse("Gallant Fox", 232.7, barn111)
-
What are the known names at memory point A? Memory point B?
Answer!
At memory point A: barn111
, secretariat
, whirlaway
At memory point B: barn111
, secretariat
, whirlaway
(no change!)
-
What does the memory look like at memory point A? Memory point B? Be consistent in your use of locations (i.e., if something is at loc01
at memory point A, and it does not change memory locations by point B, it should still be at loc01
).
Answer!
# Memory point A
(loc0001) -> Barn((loc0002), "red", 111)
(loc0002) -> {}
(loc0003) -> Horse("Secretariat", 11.1, loc0001)
(loc0004) -> Horse("Whirlaway", 777.0, loc0001)
# Memory point B
(loc0001) -> Barn((loc0002), "red", 111)
(loc0002) -> {"Secretariat" : loc0003, "Whirlaway" : loc0004, "Gallant Fox" : loc0005}
(loc0003) -> Horse("Secretariat", 11.1, loc0001)
(loc0004) -> Horse("Whirlaway", 777.0, loc0001)
(loc0005) -> Horse("Gallant Fox", 232.7, loc0001)
Question 4
Say we had the following function which defined two dictionaries, dict1 and dict2.
def fun_dictionary_function():
dict1 = {"key1" : 5, "key2" : 7}
dict2 = {"keyA" : [1, 2, 3], "keyB" : [1, 2, 3, 7]}
???
-
Which of the following code snippets could we insert where the question marks are to update the value “key1” of dict1 to be 7? Note that more than once choice might be correct.
dict1["key1"] = dict1["key1"] + 2
dict1["key1"] = 7
dict1["key1"] = dict1["key2"]
dict1["key1"] = dict1["key1"] + dict2["keyA"][1]
dict1["key1"] = dict2["keyB"][3]
Answer!
Choices A, B, C, D, and E are all correct!
-
Which of the following code snippets could we insert where the question marks are to update the value of “keyA” in dict2 to be [1, 2, 3, 7]? Note that more than one choice might be correct.
dict2["keyA"] = [1, 2, 3, 7]
dict2["keyA"] = dict2["keyB"]
dict2["keyA"].append(dict1["key2"])
dict2["keyA"] = dict2["keyA"] + 7
Answer!
A, B, and C! We cannot add 7 to dict2["keyA"]
because dict2["keyA"]
is a list.
CS111 Practice Quiz
This practice quiz is focused on memory and hashtables/dictionaries, helping to prepare you for the second quiz. Assume that all questions are worth the same amount.
Given these two dataclasses and the variations of a function to move a horse from one barn to another, answer the below questions.
@dataclass class Horse: name: str size: float barn: Barn @dataclass class Barn: residents: list[Horse] color: str id: int
Question 1
def move_horse(my_horse: Horse, new_barn: Barn): """Takes in a horse and a new barn and moves the horse to the new barn""" my_horse.barn.residents.remove(my_horse) my_horse.barn = new_barn new_barn.residents.append(my_horse) def move_horse2(my_horse: Horse, new_barn: Barn): """Takes in a horse and a new barn and moves the horse to the new barn""" my_horse.barn.residents.remove(my_horse) my_horse = Horse(my_horse.name, my_horse.size, new_barn) new_barn.residents.append(my_horse)
Now assume we ran the following code:
# Defining our horses and barns! barn111 = Barn([], "red", 111) barn180 = Barn([], "purple", 180) gallant_fox = Horse("Gallant Fox", 232.7, barn111) secretariat = Horse("Secretariat", 11.1, barn111) barn111.residents.append(gallant_fox) barn111.residents.append(secretariat)
How many Barn objects would be in memory after running this code?
Answer!
2
How many Horse objects would be in memory after running this code?
move_horse(gallant_fox, barn180) # Memory point A move_horse2(secretariat, barn180) # Memory point B
Answer!
3 (don’t forget the one created in move_horse2!)
How many lists would be in memory after running this code?
Answer!
2
Assume that gallant_fox was placed in loc 1006 and that secretariat was placed in loc 1007.
After we run
move_horse(gallant_fox, barn180)
(i.e. at memory point A), which of these horses are in a different memory location?Answer!
Neither one!
move_horse
changes barn assignments within memory, but doesn’t change the association between names and memory locationsAfter we run
move_horse2(secretariat, barn180)
(i.e. at memory point B), which memory locations are listed in the residents list forbarn180
?Answer!
From the call to
move_horse
, we know that gallant_fox’s memory location, loc 1006, is in this list. The second memory location in the list is NOT loc 1007, since it refers to the location for the new Horse that was created inmove_horse2
. The original secretariat horse isn’t listed in any barn after this call.Question 2
What if there were a huge number of horses in each barn? The
residents
list for each barn might get really difficult to iterate through if we were looking for one particular horse! Let’s consider how to make a dictionary for each barn’sresidents
instead.Part A
Assume the value for the dictionary is a
Horse
. What are some possible keys we could use for a dictionary of all the horses residing in any particular barn? What are the benefits or drawbacks of these?Answer!
Since the
Horse
dataclass has three fields,name
,size
, andbarn
, let’s think about each of these as a possible key for our dictionary.name
: Since each horse most likely has a unique name, this looks like a pretty good key. A name is also what we most likely identify a horse with: it makes sense that to get some information aboutgallant_fox
, we could look upmy_dict["Gallant Fox"]
and getgallant_fox
.size
: The size of a horse is represented by a float. We could easily imagine that two horses would be the same size, and then we could run into an issue! If we definemy_dict[232.7] = gallant_fox
and then littlesecretariat
grows up to be of size 232.7 as well, we definemy_dict[232.7] = secretariat
and thengallant_fox
is overwritten.barn
: For a similar reason tosize
, we can easily see that multiple horses living in one barn would overwrite each other. Also, in the context of this problem, this dictionary will serve as the information for a barn’s horses, so all of the horses in this dictionary will belong to the same barn and overwrite each other.Horse
dataclass to have some field that we know will be unique: for example, an “ID” field. This would allow for duplicate names, as well! Without changing our dataclass definition, however, the name might be the best choice for a key.Part B
Let’s have our dictionary map names (strings) to
Horses
for each barn, replacing the list of horses.@dataclass class Horse: name: str size: float barn: Barn @dataclass class Barn: residents: dict[str, Horse] # this is the only line of changed code color: str id: int
Complete the TODOs appropriately.
barn111 = Barn({}, "red", 111) secretariat = Horse("Secretariat", 11.1, barn111) # TODO 1: Add secretariat to barn111's residents # TODO 2: Our horse grew bigger! Change its size to 232.7 by using barn111's dictionary # (i.e. the beginning of your line should be barn111, not secretariat)
Answer!
barn111.residents[secretariat.name] = secretariat # TODO 1 barn111.residents["Secretariat"].size = 232.7 # TODO 2
Question 3
Say we have updated the
Barn
dataclass’s residents field to take in a dictionary.barn111 = Barn({}, "red", 111) secretariat = Horse("Secretariat", 11.1, barn111) whirlaway = Horse("Whirlaway", 777.0, barn111) #memory point A barn111.residents["Secretariat"] = secretariat barn111.residents["Whirlaway"] = whirlaway barn111.residents["Gallant Fox"] = Horse("Gallant Fox", 232.7, barn111) #memory point B
What are the known names at memory point A? Memory point B?
Answer!
At memory point A:
barn111
,secretariat
,whirlaway
At memory point B:
barn111
,secretariat
,whirlaway
(no change!)What does the memory look like at memory point A? Memory point B? Be consistent in your use of locations (i.e., if something is at
loc01
at memory point A, and it does not change memory locations by point B, it should still be atloc01
).Answer!
Question 4
Say we had the following function which defined two dictionaries, dict1 and dict2.
Which of the following code snippets could we insert where the question marks are to update the value “key1” of dict1 to be 7? Note that more than once choice might be correct.
#A dict1["key1"] = dict1["key1"] + 2 #B dict1["key1"] = 7 #C dict1["key1"] = dict1["key2"] #D dict1["key1"] = dict1["key1"] + dict2["keyA"][1] #E dict1["key1"] = dict2["keyB"][3]
Answer!
Choices A, B, C, D, and E are all correct!
Which of the following code snippets could we insert where the question marks are to update the value of “keyA” in dict2 to be [1, 2, 3, 7]? Note that more than one choice might be correct.
# A dict2["keyA"] = [1, 2, 3, 7] # B dict2["keyA"] = dict2["keyB"] # C dict2["keyA"].append(dict1["key2"]) # D dict2["keyA"] = dict2["keyA"] + 7
Answer!
A, B, and C! We cannot add 7 to
dict2["keyA"]
becausedict2["keyA"]
is a list.