Workshop 11: Dictionaries and Dataclasses
Topics
Dictionaries
First: What is a Dictionary? �How are they different from lists?
A dictionary is:
number_translator =
{1: "bir", 2: "iki", 3: "üç"}
1
2
3
"bir"
"iki"
"üç"
When to use Dictionaries?
Maceo has a lot of friends but is incredibly forgetful. He wants to be able to wish people a happy happy on their birthday, instead of too late or too early. �Every day, Maceo puts in the date to find out who’s birthday it is.
What kind of data structure would we want to use here?
What would our keys and values be?
birthdays = {} # str -> list[str]
birthdays["Jul 18"] = ["Isabel", "Tim", "Sohum"]
birthdays["Jul 25"] = ["Harshini"]
birthdays["Jul 16"] = ["Aidan"]
birthdays["Jun 20"] = ["Monica"]
birthdays["Nov 19"] = ["Darryl"]
birthdays["Nov 21"] = ["Ben"]
today = "Nov 21"
birthdays[today] #returns "Ben"
Dataclasses
This is how we define our own custom data type in Python (analogous to a data definition in Pyret)
Let’s say we want to make a custom data type to represent a Candy Store ...
In Pyret …
data Candy:
| candy(name :: String, flavor :: String)
end
data Store:
| store(owner :: String, candies :: List<Candy>)
end
In Python …
@dataclass
class Candy:
name : str
flavor : str
@dataclass
class Store:
owner : str
candies : list
Dataclasses
In Pyret, having two constructors is OK! But in Python… each data class has only one constructor.
We access data inside of a data class by using a .
Ex: To get to my Truck’s brand: my_truck.brand
More specifics...
data Vehicle:
| car(brand :: String, hybrid :: Boolean)
| truck(brand :: String)
end
@dataclass
class Car:
brand : str
hybrid : bool
@dataclass
class Truck:
brand : str
@dataclass
class Truck:
brand : str
my_truck = Truck("Ford")
Dataclasses are mutable...
What does that mean?
Each instance of a data class (or specific piece of data) can change!
So… what can we do with sour_candy? Will it always have the name Sour Patch Kids and flavor sour?
How can this be helpful? How can it be tricky?
from dataclasses import dataclass
@dataclass
class Candy:
name : str
flavor : str
@dataclass
class Store:
owner : str
candies : list
sour_candy = Candy("Sour Patch Kids", "sour")
Example Scenarios:
Let’s write a few functions to change our Candy Stores:
update the owner
add candies to the store
remove candies from the store
update the flavor of one of our candies
Do we need these functions to return the updated stores? If so, why? If not, what will happen inside of these functions?
What if the store comes under new management?
What if the store comes under new management?
def update_owner(our_store : Store, new_owner : str):
"""changes owner of store to new owner"""
our_store.owner = new_owner
What if our store grows?
What if our store grows?
def add_candies(our_store : Store, new_candies : list):
"""adds new candies to the store"""
for current_candy in new_candies:
our_store.candies.append(current_candy)
What if some of our candies go bad and we need to get rid of them?
What if some of our candies go bad and we need to get rid of them?
def remove_candies(our_store : Store, to_sell : list):
"""removes candies from the list of candies in the store"""
for current_candy in to_sell:
if current_candy in our_store.candies:
our_store.candies.remove(current_candy)
And the most pressing question … what if the flavor of a candy in the store changes??
And the most pressing question … what if the flavor of a candy in the store changes??
def update_new_flavor(our_store : Store, name : str, new_flav : str):
"""updates the flavor of one of the candies"""
for our_candy in our_store.candies:
if our_candy.name == name:
our_candy.flavor = new_flav
How might we go about testing these functions?
Since our functions are not returning anything, we can’t test that the output of our function is equal to something …
What could we do instead??
How might we go about testing these functions?
Since our functions are not returning anything, we can’t test that the output of our function is equal to something …
What could we do instead??
Instead, we can test that the fields of our data class have changed properly (don’t forget to also ensure that the fields that shouldn’t change stay the same!!)
Let’s look at an example of this
If we wanted to write a function to test the update_owner function we wrote earlier, we might do something like this …
Let’s look at an example of this
If we wanted to write a function to test the update_owner function we wrote earlier, we might do something like this …
def test_owner_update():
store1 = Store("Willie Wonka", [Candy("gum", "blueberry"), Candy("egg", "chocolate")])
update_owner(store1, "Charlie")
test("testing change of ownership", store1.owner, "Charlie")
test("hope candies didn’t get stolen", store1.candies, [Candy("gum", "blueberry"), Candy("egg", "chocolate")])
Questions??