-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path4_Conditionals.qmd
More file actions
946 lines (648 loc) · 33.6 KB
/
4_Conditionals.qmd
File metadata and controls
946 lines (648 loc) · 33.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
---
title: "4: Conditionals"
format:
html:
code-tools: true
revealjs:
smaller: true
scrollable: true
jupyter: python3
---
## Learning goals:
- Write Boolean expressions based on English requirements
- Explain different meta-patterns of conditional blocks (nested, chained, with alternative vs. without)
- Construct various types of conditional blocks in Python
## What are conditionals and why do we care about them?
Conditionals are an example of the fundamental computational thinking concept of **control flow**: setting up structures in our program to control what happens when. You can think of conditionals as "forks in the road" that control what happens *depending on* whether some conditions are true or false.
A set of pictures might help to give the intuition:
{fig-align="center" width="1000px"}
Basically anytime you find yourself at a problem step or part of your problem where you say something like "`do something` *based on / depending on / looking at / if* `some condition`", that is a signal that you need a conditional.
Here are some examples:
- decide what to wear: check temperature, check if i'm going to a dress code location
- shopping: check how much money i have, check quality level of the thing, what i need; decide what to buy
- decide what to eat: spiciness, taste, price
What are some other real-world examples of this sort of situation that you can think of?
## Anatomy of a basic conditional block in Python
Here's a rough diagram of a basic conditional block in Python:
{fig-align="center" width="600px"}
And here's what it looks like in code
```
# basic conditional block
if BooleanExpression:
# do something
# maybe also something more
else:
# do something else
# and maybe even more something else
```
- The **if statement**
- The if keyword signals that a conditional block is starting.
- The Boolean expression determine where to go in the conditional block
- `True` goes to the if branch; `False` goes to the else branch
- The statement needs to end in a colon to signal that the statement has ended. This is the same as with function definitions, and as we will see, with iteration loops also.
- The "if" (`True`) **branch code**: what should happen if the Boolean expression evaluates to `True`?
- Needs to be indented because of scope (same with functions; also will be true of loops)
- The **else statement**:
- Signals that an else branch will be specified next
- Just the else keyword and a colon
- The "else" (false) **branch code**: what should happen if the Boolean expression evaluates to `False`?
- Also needs to be indented
### Aside: indentation and branch code
Notice the idea of branch code: it's code that "belongs" to the branch. We only run it if we go into the branch.
In Python, we control what belongs to what with **indentation**. In other languages, you use things like curly braces (e.g., Java, Javascript).
**Note:** Unlike functions, `if`/`else` blocks do **not** create a new scope in Python. Variables assigned inside an `if` block are still accessible after the block finishes. The key thing indentation controls here is *which code runs in which branch*.
As an example, consider the following code: how many times do you think we will print the message "hello world"? Why?
```{python}
# if i have passed all the requirements for graduation, print graduate! otherwise, print need to do more
# did i accumulate at least 25 credits AND earn at least a 3.0 GPA?
n_credits = 30
gpa = 3.95
hello = "hello world!"
if n_credits >= 25 and gpa >= 3.0:
print("Go ahead")
print(hello)
else:
print("Take more classes")
print(hello)
```
The answer: only once! Because both print statements are indented inside a conditional branch, only one branch executes: either the `if` branch or the `else` branch, but never both.
### Examples of conditionals
Let's look at some examples!
The following program checks if a number is even (and prints "It's even!" if so, and "It's odd!" if not).
```{python}
num = 3
if num % 2 == 0:
print("It's even!")
else:
print("It's odd!")
```
The following program checks if a password is correct (and prints "Come in" if so, and "Go away" if not).
```{python}
user_input = "hello"
password = "bunny"
# if the user input matches the password
if user_input == password:
print("Come in")
else:
print("Go away")
```
The following program implements a Waiter checking your age on your ID, and then shows beer/alcohol menu or says "have some water"
```{python}
age = 23
drinking_age = 21
if age >= drinking_age:
print("Here's the alcohol menu")
else:
print("Have some water")
```
## A closer look at Boolean expressions
All conditional blocks depend on well-crafted **Boolean Expressions**, which are [expressions](https://joelchan.github.io/inst126-intro-programming-notes/2a_Expressions.html) that evaluate to (i.e., result in, produce) a Boolean value (i.e., `True` or `False`). This is what really determines the logic of the conditional control of flow. So you need to make sure you're proficient with Booolean expressions.
### Boolean Operators
We use **Boolean** Operators to compare TWO pieces of data. When evaluated, they yield a Boolean value (`True` or `False`).
`data1 booleanOperator data2`
Here are the main ones:
- `==` equal to / the same as
- `!=` not equal to / different from
- `>` greater than
- `>=` greater than or equal to (at least)
- `<` less than
- `<=` less than or equal to (at most)
### Logical operators
We use **Logical** operators to *combine* basic Boolean expressions into more complex ones, like "is `a` more than 3 *and* less than 5"
Here are the main ones:
- `and` (True if *all* Boolean expressions are True)
- `or` (True if *any* Boolean expression is True)
- `not` (True if the Boolean expression is *not* True)
Full list of comparison and logical operators [here](https://www.w3schools.com/python/python_operators.asp)
## Practice: Construct Boolean expressions
Let's practice! Translate these Boolean expressions from English into Python.
### Basic Boolean expressions (only Boolean operator)
```{python}
# is the driver's speed above the limit?
speed = 75
limit = 45
# boolean expression here
```
```{python}
# do i have a passport?
has_passport = True # assign the value True to the passport variable
# boolean expression here
```
### Compound Boolean expressions (Boolean operators + Logical operators)
```{python}
# have i passed all the requirements for graduation?
# which is operationalized as "do i have enough credits, with enough GPA?"
num_credits = 120 # threshold of 120
GPA = 1.5 # threshold of 2.0
# boolean expression here
```
```{python}
# did i take the prereq for the class OR get permission from the instructor?
took_prereq = False
have_permission = True
# boolean expression here
```
```{python}
# is the professor in the office and the door open more than a crack (at least 15 degrees) or there is a sign that says come on in or you have an appointment?
prof_in_office = True
door_angle = 5
sign_says = "Come in"
have_appointment = True
# boolean expression here
```
#### More practice: compound Boolean expressions
Try these on your own! Each one requires combining Boolean operators with logical operators (`and`, `or`, `not`).
#### 1. Can I ride the roller coaster?
You can ride the roller coaster if you are at least 48 inches tall AND at least 8 years old. Write a Boolean expression that checks both conditions.
```{python}
height_inches = 50
age = 7
# boolean expression here
```
#### 2. Is the restaurant open?
The restaurant is open if the hour is between 11 and 14 (lunch) OR between 17 and 21 (dinner). Write a Boolean expression that checks if the restaurant is currently open. Assume the hour is in 24-hour time (e.g., 13 = 1pm).
```{python}
hour = 13
# boolean expression here
```
#### 3. Can I get a discount?
You get a discount if you are a student OR a senior (65 or older).
```{python}
is_student = False
age = 70
# boolean expression here
```
#### 4. Should I bring an umbrella?
You should bring an umbrella if it is raining OR if the chance of rain is above 50% and you don't have a rain jacket.
```{python}
is_raining = False
chance_of_rain = 75
has_rain_jacket = False
# boolean expression here
```
#### 5. Can I register for the class?
You can register for the class if you have taken the prerequisite AND (you are a junior or senior, based on credits: junior is at least 60, senior is at least 90).
```{python}
took_prereq = True
credits = 55
# boolean expression here
```
#### 6. Is the flight delayed?
A flight is delayed if the wind speed is above 40 mph OR (visibility is below 3 miles AND it is not a clear day).
```{python}
wind_speed = 25
visibility = 2
is_clear = False
# boolean expression here
```
## Practice: construct basic conditional blocks
Now let's practice constructing conditional blocks! Follow along with me to translate these English instructions into conditional blocks. We basically need to 1) decide what the condition is and translate it into a Boolean expression, then 2) decide what actions go in the `True` or `False` branches.
If my speed is above the limit, print stop; otherwise, let me pass.
```{python}
# if my speed is above the limit, print stop; otherwise, let me pass
speed = 25
limit = 45
# conditional block below here
```
If i have a passport, print come on in; otherwise, print go away
```{python}
# if i have a passport, print come on in; otherwise, print go away
# do i have a passport?
has_passport = False # assign the value True to the passport variable
# conditional block below here
```
if i have passed all the requirements for graduation, print graduate! otherwise, print need to do more
```{python}
# if i have passed all the requirements for graduation, print graduate! otherwise, print need to do more
# did i accumulate at least 120 credits AND earn at least a 2.0 GPA?
# did i take the prereq for the class OR get permission from the instructor?
num_credits = 110 # threshold of 120
GPA = 1.9 # threshold of 2.0
# conditional block below here
```
#### More practice: basic if/else
Try these on your own! Each one needs a basic if/else block.
#### 1. Freezing check
If the temperature is below freezing (32 degrees F), print "It's freezing!"; otherwise, print "It's not freezing."
```{python}
temp = 28
# conditional block below here
```
#### 2. Pass or fail
If the student's score is at least 60, print "Pass"; otherwise, print "Fail".
```{python}
score = 55
# conditional block below here
```
#### 3. Number guessing game
If the user's guess matches the secret number, print "You got it!"; otherwise, print "Try again!"
```{python}
guess = 7
secret_number = 4
# conditional block below here
```
#### 4. Shopping decision
If the item is on sale AND you have enough money (i.e., money is at least the price), print "Buy it!"; otherwise, print "Maybe next time."
```{python}
on_sale = True
price = 25
money = 20
# conditional block below here
```
## More complex conditional structures
The if / else conditional block is the most basic and easy to understand. But often your programs may require something a bit simpler, and sometimes a bit more complex.
### Conditional execution
The `else` branch is actually optional. Sometimes you just want to do something if it's true, otherwise you do nothing.
The flow looks like this:
{fig-align="center" width="600px"}
Some examples:
- Only stop someone if they're above the speed limit
- Tell me if someone is coming!
- Look through the bag and only pull out the red skittles
Can you think of any others?
```
# generic
if booleanExpression:
# do something
```
```{python}
speed = 25
limit = 30
if speed > limit:
print("Stop!")
```
Keywords/phrases that signal that this is appropriate?
- if only one "choice" (or action) is described, then probably you don't need an else, since "doing nothing" is a default action
#### Practice: conditional execution (no else)
Try these on your own! Each one only needs an `if` — no `else` needed.
#### 1. Low battery warning
If the battery level is below 20, print "Low battery warning!"
```{python}
battery_level = 15
# conditional block below here
```
#### 2. Dean's list
If the student is on the dean's list (GPA of 3.5 or above), print a congratulations message.
```{python}
gpa = 3.8
# conditional block below here
```
#### 3. Password length check
If the password is less than 8 characters long, print "Warning: password is too short!" Hint: you can use `len()` to get the length of a string, e.g., `len("hello")` returns 5.
```{python}
password = "abc"
# conditional block below here
```
#### 4. Free gift threshold
If the order total is at least $50, print "Free gift added to your order!"
```{python}
order_total = 62
# conditional block below here
```
#### 5. Weekend check
If it's the weekend (Saturday or Sunday), print "No class today!"
```{python}
day = "Saturday"
# conditional block below here
```
### Chained conditionals
Sometimes you have more than two *mutually exclusive* choices of paths (branches). In that case you need an elif.
The difference from the basic conditional is something like this:
{fig-align="center" width="600px"}
Some examples:
- you have a fever if you're above 100, hypothermia if you're under 95; otherwise, you're all good!
- choosing an outfit depending on where you want to go (in the Spring in Maryland!).
- choosing a football play depending on what you think the defense is showing.
Any other examples?
The key difference between this type of conditional block and the regular "if/else" blocks is that you need more than one Boolean expression; one for each `if` or `elif` statement.
Here's the generic structure:
```
if someCondition:
# then something
elif someOtherCondition:
# then something else
else:
# some default (this is technically optional
# but if you leave it out, you may have some unexpected edge cases you didn't account for!
```
```{python}
gpa = 3.5
gpa_threshold = 2.0
required_courses = 8
req_threshold = 10
if gpa >= gpa_threshold and required_courses >= req_threshold:
print("graduate!")
elif gpa >= gpa_threshold and required_courses < req_threshold:
print("take more required courses")
elif gpa < gpa_threshold and required_courses >= req_threshold:
print("take an easy course!")
else:
print("talk to an advisor")
```
```{python}
# example
temp_f = 97
if temp_f >= 100:
print("fever!")
elif temp_f < 95: # need another Boolean expression
print("hypothermia!")
else:
print("all good!")
```
Keywords/phrases that signal that this is appropriate?
When you see more than two *mutually exclusive* **conditions** or **choices**
Practice! Let's translate these English instructions into Python conditional blocks.
ticket pricing: if you're under 5 or 65 and up, price is zero; if you're theater staff, you get half price (7.50); otherwise pay normal price (15)
```{python}
# ticket pricing:
# if you're under 5 or 65 and up, price is zero;
# if you're theater staff, you get half price (7.50);
# otherwise pay normal price (15)
age = 65
theater_staff = True
# chained conditional block below here
```
help me write the grader for late assignments: if you submit before target date, you get full credit; if you submit after the target date, but before the last day of the period, you get 85% credit - if you submit on the last day of period, you get 70% credit
```{python}
# help me write the updated grader for your PCEs:
# if you submit before target date, you get full credit;
# if you submit after the target date, but before or equal 1 week threshold, you get 85% credit
# if you submit after 1 week threshold, but before or equal to 2 week threshold, you get 70% credit
# otherwise, you get no credit
submission_date = 35
target_date = 36
one_week_threshold = target_date + 7
two_week_threshold = target_date + 14
score = 1
# chained conditional block below here
```
#### More practice: chained conditionals
Try these on your own! Each one needs an if/elif/else block.
#### 1. Letter grade converter
If the score is 90 or above, print "A". If 80-89, print "B". If 70-79, print "C". If 60-69, print "D". Otherwise, print "F".
```{python}
score = 85
# chained conditional block below here
```
#### 2. Shipping cost calculator
If the order weighs less than 1 lb, shipping is $3. If it weighs 1-5 lbs, shipping is $7. If it weighs more than 5 lbs, shipping is $12. Print the shipping cost.
```{python}
weight = 3.5
# chained conditional block below here
```
#### 3. Time of day greeting
Using 24-hour time (0 = midnight, 13 = 1pm, etc.): if the hour is less than 12, print "Good morning!" If 12-16, print "Good afternoon!" If 17-20, print "Good evening!" Otherwise, print "Good night!"
```{python}
hour = 14
# chained conditional block below here
```
#### 4. Water state
If the temperature (Celsius) is 0 or below, print "Solid (ice)". If above 100, print "Gas (steam)". Otherwise, print "Liquid (water)".
```{python}
temp_c = 105
# chained conditional block below here
```
#### 5. BMI category calculator
If BMI is below 18.5, print "Underweight". If 18.5 to 24.9, print "Normal weight". If 25.0 to 29.9, print "Overweight". If 30.0 or above, print "Obese".
```{python}
bmi = 22.5
# chained conditional block below here
```
#### More practice: chained conditionals with multiple variables
The previous problems mostly involved checking one variable against different thresholds. These problems require you to consider **two or more variables** together to decide what to do. Try building a decision table first to help you think through the cases!
#### 6. Study advice
Give a student study advice based on their grade AND how many hours they study per week. If their grade is below 70 and they study less than 10 hours, print "You need to study more!". If their grade is below 70 but they study 10 or more hours, print "Let's review your study strategies." If their grade is 70 or above and they study less than 5 hours, print "You're doing well, but don't get complacent!" Otherwise, print "Keep up the good work!"
```{python}
grade = 65
study_hours = 12
# chained conditional block below here
```
#### 7. Parking fee calculator
A parking garage charges based on the type of vehicle AND how long you park. For motorcycles: $2 if 2 hours or less, $5 if more than 2 hours. For cars: $5 if 2 hours or less, $12 if more than 2 hours. For trucks: $10 if 2 hours or less, $20 if more than 2 hours. Print the fee.
```{python}
vehicle = "car"
hours_parked = 3
# chained conditional block below here
```
#### 8. Movie recommendation
Recommend a movie based on the viewer's preferred genre AND their age. If they like "action" and are under 13, print "The Incredibles". If they like "action" and are 13 or older, print "Mad Max". If they like "comedy" and are under 13, print "Despicable Me". If they like "comedy" and are 13 or older, print "The Grand Budapest Hotel". For any other genre, print "Browse the catalog."
```{python}
genre = "comedy"
age = 10
# chained conditional block below here
```
#### 9. Shipping speed selector
An online store offers shipping options based on the order total AND whether the customer is a member. If the total is at least $50 and the customer is a member, print "Free 2-day shipping". If the total is at least $50 and not a member, print "Free standard shipping". If the total is less than $50 and a member, print "$3 standard shipping". If the total is less than $50 and not a member, print "$7 standard shipping".
```{python}
order_total = 35
is_member = True
# chained conditional block below here
```
### Planning your conditionals with decision tables
As your conditional blocks get more complex (especially with chained conditionals), it gets harder to keep track of all the possible situations your code needs to handle. A **decision table** is a simple but powerful planning tool: you list out all the possible combinations of your conditions, and then decide what should happen in each case. Think of it as a spreadsheet for your logic.
#### Why bother?
Consider the ticket pricing example above. The English description says:
- under 5 or 65 and up → free
- theater staff → half price
- otherwise → full price
But what if someone is 3 years old *and* theater staff? Should they get free or half price? The English description doesn't tell us! A decision table forces you to confront these situations *before* you write code.
#### How to build a decision table
**Step 1:** Identify your conditions (the things you're checking). For ticket pricing, that's: (a) is the person under 5 or 65+? and (b) are they theater staff?
**Step 2:** List every combination of True/False for those conditions. With 2 conditions, you get 4 rows:
| under 5 or 65+ | theater staff | price |
|---|---|---|
| True | True | ??? |
| True | False | $0 |
| False | True | $7.50 |
| False | False | $15 |
**Step 3:** Fill in what should happen for each row. That `???` is exactly the kind of edge case that causes bugs! You need to make a decision: let's say young kids and seniors always get in free, even if they're also staff. Now the table becomes:
| under 5 or 65+ | theater staff | price |
|---|---|---|
| True | True | $0 |
| True | False | $0 |
| False | True | $7.50 |
| False | False | $15 |
**Step 4:** Now your conditional block almost writes itself. Looking at the table, you can see that the age condition should be checked *first*, since it applies regardless of staff status:
```{python}
age = 3
theater_staff = True
if age < 5 or age >= 65:
price = 0
elif theater_staff:
price = 7.50
else:
price = 15
print(f"Price: ${price}")
```
Notice how the order of the `if`/`elif` matters here! If we checked `theater_staff` first, we'd accidentally charge a 3-year-old staff member $7.50.
#### Practice: build a decision table
Try building a decision table for the late assignment grader exercise above. What are the conditions? How many rows do you need? Are there any edge cases where it's not obvious what should happen?
### Nested conditionals
Sometimes it only makes sense to check a condition if earlier conditions are true/false. This is like a garden of forking paths or choose your own adventure. Sometimes this to save time/operations. Other times, it may make your program more readable.
I like to think of it like a choose your own adventure maze:
{fig-align="center" width="600px"}
Simple example: I want to know if x is the same, less than, or greater than y. We can represent this as a chained conditional with three conditions. But we can also group the less than or greater than conditional block by itself since that only make sense in the situation where x and y are *not* the same (i.e., `x != y`).
```{python}
x = 5
y = 10
if x == y:
print("x and y are equal")
else:
if x < y:
print("x is less than y")
else:
print("x is greater than y")
```
Another simple example: graduation requirements: if you've completed the base requirements and you have a 3.0 average, then we check: do you have sufficient electives? if yes, then great! if not, take more electives. if you don't have the core requirements done, then you need to take care of that first, we'll worry about electives later.
```{python}
n_credits = 125
credit_threshold = 120
GPA = 3.5
n_electives = 3
electives_threshold = 4
if n_credits >= credit_threshold and GPA >= 3.0:
if n_electives >= electives_threshold:
print("Ready to graduate!")
else:
print("Get more electives!")
else:
print("Finish core requirements with sufficient GPA!")
```
Keywords/phrases that signal that this is appropriate? Something about having more than two choices, but some choices only make sense if some earlier condition is met. In other words, we have more of multiple forks, rather than a single fork.
Practice! Let's translate these English instructions into Python conditional blocks.
Polling booth: if you don't have an id, go away and register, then come back; if you have an id come on in! then, if you need assistance, go to the assisted booth; otherwise, go to the normal booth.
```{python}
# polling booth: if your registration doesn't match this location, go away to the right place; if yes, then come on in!
# then, if you need assistance, go to the assisted booth; otherwise, go to the normal booth.
registration_here = True
need_assistance = False
# nested conditional block below here
```
#### More practice: nested conditionals
Try these on your own! Each one involves a condition that only makes sense to check after an earlier condition.
#### 1. Online store checkout
If the user is logged in, check if they have items in their cart: if yes, print "Proceeding to checkout"; if no, print "Your cart is empty". If the user is not logged in, print "Please log in first".
```{python}
logged_in = True
items_in_cart = 0
# nested conditional block below here
```
#### 2. Amusement park ride
If the rider is tall enough (at least 48 inches), then check their age: if they are under 12, print "You need an adult with you"; otherwise, print "Enjoy the ride!" If they are not tall enough, print "Sorry, you're too short for this ride".
```{python}
height = 50
age = 10
# nested conditional block below here
```
#### 3. Job application screener
If the applicant has a degree, check their years of experience: if 3 or more years, print "Schedule an interview"; otherwise, print "Consider for junior position". If they don't have a degree, check their years of experience: if 5 or more years, print "Schedule an interview"; otherwise, print "Does not meet requirements".
```{python}
has_degree = False
years_experience = 6
# nested conditional block below here
```
#### 4. Restaurant order
If the restaurant is open, check if the item is on the menu. If yes, check if the item is in stock: if yes, print "Order placed!"; if no, print "Sorry, that item is sold out". If the item is not on the menu, print "We don't serve that here". If the restaurant is closed, print "Sorry, we're closed".
```{python}
is_open = True
on_menu = True
in_stock = False
# nested conditional block below here
```
#### 5. Email filter
If the email is from a known contact, print "Inbox". If the email is not from a known contact: if it contains the word "unsubscribe", print "Promotions"; otherwise, print "Unknown - review manually".
```{python}
from_known_contact = False
contains_unsubscribe = True
# nested conditional block below here
```
#### More practice: nested conditionals (dependent/sequential questions)
The key idea behind nested conditionals is that some questions **only make sense to ask after you've answered an earlier question**. Think of it like a flowchart or a phone tree: the first question determines which *path* you're on, and then you face different follow-up questions depending on that path. This is different from chained conditionals, where all the conditions are answering the *same* question (e.g., "what range is the score in?").
A good test: if the inner question would be **meaningless or irrelevant** without knowing the answer to the outer question, that's a signal to use nesting.
#### 6. Tech support troubleshooter
A user calls tech support. First, ask: is the device turning on? If it's not turning on, check if it's plugged in: if it's not plugged in, print "Plug in the device and try again"; if it is plugged in, print "The device may be broken - schedule a repair". If the device IS turning on, then check: is the screen displaying anything? If yes, print "Try restarting the application"; if no, print "The display may need replacement".
Notice how the "is it plugged in?" question only makes sense if the device isn't turning on, and the "is the screen displaying?" question only makes sense if it IS turning on. These are *different follow-up questions* depending on the first answer.
```{python}
device_turns_on = False
is_plugged_in = False
screen_displays = True
# nested conditional block below here
```
#### 7. Financial aid advisor
First check: does the student have financial need (family income below $50,000)? If yes, check their GPA: if GPA is 3.5 or above, print "Eligible for full scholarship"; if GPA is below 3.5, print "Eligible for need-based grant". If the student does NOT have financial need, check if they have financial need is irrelevant now -- instead check their GPA: if GPA is 3.8 or above, print "Eligible for merit scholarship"; otherwise, print "No financial aid available".
Notice: the GPA thresholds are *different* depending on whether the student has financial need. This is why nesting makes sense here -- it's not just "check income, then check GPA" independently. The *meaning* of the GPA check changes based on the income answer.
```{python}
family_income = 45000
gpa = 3.6
# nested conditional block below here
```
#### 8. Package delivery router
First, check if the package is domestic or international. If domestic, check the size: if it's "small", print "Send via regular mail"; if it's "large", print "Send via ground shipping". If international, check if the destination country requires customs forms: if yes, print "Fill out customs form, then send via international courier"; if no, print "Send via international courier".
The key insight: the follow-up question for domestic packages (what size?) is completely different from the follow-up question for international packages (customs forms needed?). These are different paths with different decision points.
```{python}
is_domestic = False
package_size = "small"
needs_customs = True
# nested conditional block below here
```
#### 9. Customer complaint handler
First, check if the customer has a valid receipt. If they do, check what they want: if they want a "refund", print "Process refund to original payment method"; if they want an "exchange", print "Help customer find replacement item". If they do NOT have a receipt, check if the purchase amount is under $20: if yes, print "Offer store credit as a courtesy"; if no, print "Sorry, we need a receipt for returns over $20".
Notice how having a receipt vs. not leads to entirely different sets of options. With a receipt, we ask "refund or exchange?" Without one, we check the dollar amount instead -- a completely different question.
```{python}
has_receipt = False
wants = "refund"
purchase_amount = 15
# nested conditional block below here
```
Some people may say that sometimes this sort of code isn't great practice, because it can be hard to understand and debug. I'm not sure I completely agree. I think it depends on the structure of your problem. I like to write nested conditionals when the underlying logic is really like a garden of forking paths or choose your own adventure game.
## Common errors
### Syntax and indentation errors
e.g., forgetting the colon, or forgetting to indent
Best recommendation is to use templates for now as you set them up.
### Boolean expression errors
Most commonly, using `=` (this is assigning!) instead of `==` (the Boolean operator you actually want)!
### Semantic errors
Not covering all your bases or mapping the wrong conditions to outcomes. These are the trickiest because your code runs without errors, but it does the wrong thing!
Common examples:
- Checking conditions in the wrong order (e.g., a more general condition "catches" cases before a more specific one gets a chance)
- Forgetting an edge case (e.g., what if two conditions are both true at the same time?)
- Using `and` when you mean `or`, or vice versa
The best defense against semantic errors is to **build a decision table** before you write your conditional block (see the [decision tables section above](#planning-your-conditionals-with-decision-tables)). Listing out every combination of conditions and deciding what should happen in each case helps you spot gaps and conflicts in your logic before they become bugs.
Example decision table for Project 1: https://docs.google.com/spreadsheets/d/1-q5XXbMDoji8AMVWxgUf5GW5CUOJfiWQTTV6u0-DwF8/edit?usp=sharing
You can also use decision tables to **debug** existing code: build the table from your code by tracing through each row, and compare it to what you *intended*. If they don't match, you've found your bug.
### Using separate `if` blocks instead of `elif`
A very common mistake is writing multiple separate `if` statements when you actually need a chained conditional (`if`/`elif`/`else`). These look similar but behave very differently!
Consider this example: assign a letter grade based on a score.
**Wrong (separate `if` blocks):**
```{python}
score = 85
if score >= 90:
grade = "A"
if score >= 80:
grade = "B"
if score >= 70:
grade = "C"
if score >= 60:
grade = "D"
else:
grade = "F"
print(grade)
```
This prints `"D"`! Why? Because each `if` is a **separate** conditional block — they all run independently. So even though `score >= 90` is `False`, the program keeps going and checks every other `if`. When it gets to `score >= 80`, that's `True`, so `grade` becomes `"B"`. But then it *keeps checking*: `score >= 70` is also `True`, so `grade` gets overwritten to `"C"`. Then `score >= 60` is also `True`, so `grade` gets overwritten again to `"D"`.
**Right (chained conditional with `elif`):**
```{python}
score = 85
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
elif score >= 70:
grade = "C"
elif score >= 60:
grade = "D"
else:
grade = "F"
print(grade)
```
This correctly prints `"B"`. With `elif`, once a condition is `True` and its branch runs, the rest of the chain is **skipped**. That's the whole point of chaining: the conditions are *mutually exclusive* — only one branch ever executes.
**The rule of thumb:** if your conditions are meant to be mutually exclusive (only one should "win"), use `elif` to chain them together. Use separate `if` blocks only when the conditions are truly independent and you want *each one* checked regardless of the others.