Class 20 - Conditional data
Date: October 28, 2026
⚠️Homework
Homework 7 due November 1, 2026
‼️Ending Skills
Last week for skills: 10, 11
🆕New Skills
First week for skills: 5
Skills: 6
Notes (review before class)
Conditional Data
- Conditional data: a type with several kinds of values, called variants, each with its own details. It's an "or": a traffic light is red or yellow or green; a zoo animal is a boa or an armadillo or ...
- Sometimes we care which variant we have (a driver at a light), sometimes not (counting zoo animals).
Defining Conditional Data
One dataclass per variant, then a name for the type that is any of them:
from dataclasses import dataclass
@dataclass
class Red:
pass
@dataclass
class Yellow:
pass
@dataclass
class Green:
pass
TLColor = Red | Yellow | Green
- Each
|("or", as infloat | stron Class 12) adds a variant. - A variant with no fields has the body
pass("nothing here"). Making one still takes():Red().
Variants can have fields:
@dataclass
class Boa:
name: str
length: float
@dataclass
class Armadillo:
name: str
liveness: bool
Animal = Boa | Armadillo
b1 = Boa("Ayisha", 10)
b2 = Boa("Bonito", 8)
a1 = Armadillo("Glypto", True)
- One type,
Animal, with two constructors,BoaandArmadillo. - Annotate an example with its variant (
b1: Boa) or the whole type (b1: Animal, losing the distinction). - Structured data (like
ITunesSong, Class 19) is the case with one variant. - Python's built-in
Nonemeans "no value";str | Noneis "a string, orNone" (Class 24 uses it).
Telling Variants Apart: match
b1.length is fine, since b1 is a Boa; but for any Animal a, a.length
is an error when a is an Armadillo. Instead, match has a case for
each variant:
def advice(c: TLColor) -> str:
"""returns advice for a driver at a light of color c"""
match c:
case Red():
return "wait!"
case Yellow():
return "get ready..."
case Green():
return "go!"
Try: leave out the () in case Red():. Then leave out the Red case, and
try both advice(Yellow()) and advice(Red()).
Fields in a case
A case can list names for the variant's fields, in order; while that case
runs, they are in the directory (no . needed):
def animal_name(a: Animal) -> str:
"""returns the name of any animal"""
match a:
case Boa(n, l):
return n
case Armadillo(n, l):
return n
def test_animal_name():
assert animal_name(b1) == "Ayisha"
assert animal_name(b2) == "Bonito"
assert animal_name(a1) == "Glypto"
- The names needn't match the fields': fields get long names; cases, short ones.
animal_name(b2):b2isBoa("Bonito", 8), so the first case matches, withnas"Bonito"andlas8; it returns"Bonito".
Recap (15 mins)
A payment system records how each payment was made: in cash, by credit card (with its number and expiration date), or by check (with the bank account, routing number, and check number). Read through the program:
from dataclasses import dataclass
@dataclass
class Cash:
pass
@dataclass
class Credit:
card_number: str
expiry: str
@dataclass
class Checking:
bank_account: str
routing: str
check_number: int
PaymentMethod = Cash | Credit | Checking
payment_1 = Cash()
payment_2 = Credit("1111-2222-3333-4444", "09/26")
payment_3 = Checking("987654321", "111", 55)
def display_payment(p: PaymentMethod) -> str:
"""describes how p was paid, for a receipt"""
match p:
case Cash():
return "Paid in cash"
case Credit(cn, exp):
return "Paid by credit card expiring on " + exp
case Checking(acc, rout, num):
return "Paid by check from account " + acc
def test_display_payment():
assert display_payment(payment_1) == "Paid in cash"
assert display_payment(payment_2) == "Paid by credit card expiring on 09/26"
assert display_payment(payment_3) == "Paid by check from account 987654321"
- What does
display_payment(Checking("24680", "135", 7))return? Which names does itscaseadd to the directory, and with what values? payment_2.expiryis"09/26". Why doesdisplay_paymentusematch, rather thanp.expiry?- To also accept gift cards, each with a card number and a balance, what would you add, and where?
Class Exercises (40 mins)
- Define a
Vehicledata type with three variants:Bike(no fields),Car(withmakeandyearfields), andTruck(withmake,year, andcapacityfields). Create one example of each variant. - Write a function
vehicle_agethat takes aVehicleand the current year, and returns the age in years. For bikes, return 0. - Define a
Gradedata type with variants:Letter(with a string field for A/B/C/D/F),Percent(with a number field), andPassFail(with a boolean field). Create examples of each. - Write a function
grade_to_gpathat converts anyGradeto a 4.0 scale number. Use:A=4.0, B=3.0, C=2.0, D=1.0, F=0.0; percentages:90+=4.0, 80-89=3.0, 70-79=2.0, 60-69=1.0, <60=0.0; pass-fail:pass=4.0, fail=0.0. - Write a function
payment_summarythat takes aPaymentMethodand returns a string: "Cash payment", "Card ending in XXXX" (last 4 digits), or "Check #NNNN" (check number). - Define a
WeatherReportwith variants:Sunny(temperature only),Rainy(temperature and precipitation amount), andSnowy(temperature, precipitation, and wind speed). Write a functionis_severethat returnsTrueif: rainy with >2 inches, snowy with >30 mph wind, or sunny above 95°F.
Wrap-up (5 mins)
- Conditional data represents information that can take one of several different forms.
- Use
matchto process conditional data, handling each possible variant. - Different variants can have different numbers and types of fields.