Skip to main content

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 in float | str on 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, Boa and Armadillo.
  • 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 None means "no value"; str | None is "a string, or None" (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): b2 is Boa("Bonito", 8), so the first case matches, with n as "Bonito" and l as 8; 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 its case add to the directory, and with what values?
  • payment_2.expiry is "09/26". Why does display_payment use match, rather than p.expiry?
  • To also accept gift cards, each with a card number and a balance, what would you add, and where?

Class Exercises (40 mins)​

  1. Define a Vehicle data type with three variants: Bike (no fields), Car (with make and year fields), and Truck (with make, year, and capacity fields). Create one example of each variant.
  2. Write a function vehicle_age that takes a Vehicle and the current year, and returns the age in years. For bikes, return 0.
  3. Define a Grade data type with variants: Letter (with a string field for A/B/C/D/F), Percent (with a number field), and PassFail (with a boolean field). Create examples of each.
  4. Write a function grade_to_gpa that converts any Grade to 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.
  5. Write a function payment_summary that takes a PaymentMethod and returns a string: "Cash payment", "Card ending in XXXX" (last 4 digits), or "Check #NNNN" (check number).
  6. Define a WeatherReport with variants: Sunny (temperature only), Rainy (temperature and precipitation amount), and Snowy (temperature, precipitation, and wind speed). Write a function is_severe that returns True if: 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 match to process conditional data, handling each possible variant.
  • Different variants can have different numbers and types of fields.