← Back to the Introduction to Computer Science outline The Course Maker
← Introduction to Computer Science outline
Week 4 · Chapter

Chapter 4 — Booleans & Conditionals

Introduction to Computer Science Free sample edition

The module's primary reading · ~35–45 minutes · Objective 3 (write Boolean expressions with comparison and logical operators, read and build a truth table, and control which code runs with if, elif, and else) · Read it first this week; the lecture, the slides, the tutorial, the quiz, and the Coding Lab all build on it.


In plain language

Until now, every program you wrote ran every line, top to bottom, every time, but this week your programs start making choices. You will ask yes-or-no questions with comparisons (tests such as "is 45 at least 300?") that Python answers with True or False. You will join questions together with the words and, or, and not (the joining words that build a bigger yes-or-no question). Then you will use if statements (instructions that run some lines only when a question comes out True) so a program can say "Keep going" on one run and "Goal met" on another. As always, you predict what each program prints and then run it to check.

Why you already care about this

A thermostat set to 18 degrees reads the room at 17 and switches the heat on. A bike-share dock shows 0 free bikes, so the app tells you to try the next station. A sign-up form counts the 11 characters in your new password and lets it through, because the rule asks for at least 8. None of these devices is clever. Each one asks a yes-or-no question and then picks one of two paths.

That is the whole idea of this week. A program compares two values, gets back True or False, and lets the answer decide which lines run. The reading log you have been building learns to do it too: it checks how far you are from your 300-page goal and prints a different message for each case.

There is a catch, and it is the most important sentence in the chapter. Python checks its questions in the order you wrote them and stops at the first one that comes out True. Put the questions in the wrong order and the program still runs, but it says the wrong thing.

By the end of this chapter you will be able to:

  • write a comparison with any of the six comparison operators and predict whether it gives True or False;
  • keep = and == apart in every line you write;
  • combine conditions with and, or, and not, and fill in a truth table in the standard row order;
  • work out a mixed condition in Python's order, not, then and, then or;
  • predict which single branch of an if, elif, and else chain runs;
  • tell a SyntaxError from a logic error in a conditional and fix each one.

Carry this line with you: Python runs the first true branch — not the best one.

Where we are

  • Already covered: Week 1 taught you to predict, then run, and to read an error from its last line. Week 2 gave you variables, the four core types, and the bool values True and False. Week 3 taught you to read input as a string and build output with f-strings.
  • This week: comparison operators, the logical operators and, or, and not, truth tables, and if, elif, and else.
  • How they connect: the bool type you named in Week 2 finally gets a job, because every comparison produces one, and every if statement reads one.
  • Where we're going next: Week 5, Loops I: The while Loop, uses this week's conditions to decide whether a block runs again, so a condition you can read now becomes a loop you can control.

Week 1 gave you the habit you will lean on most: the computer does exactly what you wrote, not what you meant. Week 2 named True and False as the two values of type bool and warned that = and == are different; this chapter teaches == fully. Week 2 also gave you //, floor division, which the reading log uses again this week to find half of its goal. And Week 1's SyntaxError returns in Section 5, this time caused by a single missing = sign.

1. Ask a yes-or-no question: comparison operators

A shop clerk checking an age on an ID card is not doing arithmetic. The clerk asks one question, "is this number at least 18?", and the only possible answers are yes and no. Python asks questions like that all the time, and it answers with True or False.

A Boolean expression is an expression that Python works out to one of the two bool values, True or False, such as pages_read >= goal.

You build most Boolean expressions with a comparison operator, one of the six operators ==, !=, <, >, <=, and >= that compare two values and give True or False.

The six operators, in plain words:

  • == asks "is equal to?"
  • != asks "is not equal to?"
  • < asks "is less than?" and > asks "is greater than?"
  • <= asks "is less than or equal to?" and >= asks "is greater than or equal to?"

One of them needs its own name, because it looks so much like a symbol you already know. The equality operator is the == operator, which asks whether two values are equal and gives True or False, unlike =, which gives a name a value.

Worked example — the reading log asks three questions. Your goal is 300 pages, and you have read 45. Predict all three lines before you read the output.

goal = 300
pages_read = 45
print(pages_read >= goal)
print(pages_read == 45)
print(pages_read != 45)

Output

False
True
False

Line 3 asks whether 45 is at least 300. It is not, so Python prints False. Line 4 asks whether pages_read holds 45. It does, so Python prints True. Line 5 asks whether pages_read is not 45, and that is False. In words: a comparison does not change any value; it only answers a question about the values.

Notice that print shows True and False without quotation marks. They are not text. They are the two values of type bool, written with a capital first letter.

Worked example — a number and a string. Python compares values, so a whole number and a float with the same value are equal. A string is never equal to a number, even when it shows the same digit.

print(3 == 3.0, "3" == 3)

Output

True False

The whole number 3 and the float 3.0 hold the same value, so the first comparison is True. The string "3" is text, so it does not equal the number 3, and the second comparison is False. In words: == compares values, and a str and an int never share a value.

Comparisons work on any values you have already met. A thermostat program can ask temperature < 18; with temperature = 17, the line print(temperature < 18) prints True. A sign-up form can ask len(password) >= 8; with password = "sunflower42", which has 11 characters, the line print(len(password) >= 8) prints True.

Misconception check. Students often think = and == are interchangeable, because both are read aloud as "equals" in everyday speech. They are not. = is an instruction: give the name on the left the value on the right. == is a question: are these two values equal? The cure is to read every = aloud as "gets" and every == aloud as "is equal to", and to say the right word before you type the symbol.

In practice (your tools). In your browser runner, type print(45 >= 300) and press Run, then change the operator to each of the other five in turn and predict each output before you run it. The Python Language Reference on docs.python.org lists all six operators in its section 6.10 on comparisons.

Memory hook: = gets a value; == asks a question.

2. Combine questions: and, or, not, and truth tables

A bike-share app will unlock a bike only if you have a pass and the dock has a free bike. A cinema gives a discount if you are a student or you come before noon. Real decisions often join two questions together, and Python has three words for joining them.

A logical operator is one of the three words and, or, and not, which combine or flip Boolean values to build a bigger condition.

  • and — The logical operator that gives True only when the conditions on both of its sides are True.
  • or — The logical operator that gives True when at least one of its sides is True, and False only when both sides are False.
  • not — The logical operator that flips one Boolean value, so not True is False and not False is True.

Worked example — the bike-share dock. You have a pass, but the dock has 0 free bikes. Predict all three lines.

has_pass = True
bikes_free = 0
print(has_pass and bikes_free > 0)
print(has_pass or bikes_free > 0)
print(not has_pass)

Output

False
True
False

Line 3: has_pass is True, but bikes_free > 0 is 0 > 0, which is False. With and, one False side is enough to make the whole thing False, so no bike unlocks. Line 4: with or, one True side is enough, so it prints True. Line 5: not flips True to False. In words: and needs both, or needs either, and not flips one.

You can list every possible case in a grid. A truth table is a table that lists every combination of True and False for its inputs, one row each, beside the value an expression gives on that row. This course always lists the rows in one order: True True, then True False, then False True, then False False.

Worked example — the truth table, produced by running it. Rather than fill in the table from memory, let Python print every row.

for a in (True, False):
    for b in (True, False):
        print(a, b, a and b, a or b)
for a in (True, False):
    print(a, not a)

Output

True True True True
True False False True
False True False True
False False False False
True False
False True

The program uses a loop, which Weeks 5 and 6 teach; for now, read it as "try every pair of values and print one line for each." Each of the first four lines gives a, b, a and b, and a or b, in that order. The last two lines give a and not a. Here are the first four lines as a table.

Truth table for and and or over the two inputs a and b, in the course's standard row order
a b a and b a or b
True True True True
True False False True
False True False True
False False False False

Read down the a and b column: it is True on the first row only, the one row where both inputs are True. Read down the a or b column: it is False on the last row only, the one row where both inputs are False. And from the last two lines of the output, not True is False and not False is True.

Misconception check. Students often think or means "one or the other, but not both," because that is how people use the word in conversation ("soup or salad"). In Python, or is True on the first row too, where both sides are True. The cure is to check the truth table rather than your ear: True or True is True.

In practice (your tools). Paste the truth-table program into your browser runner and run it. Then change the print line to show not a or b instead of a and b, predict the four new values on paper, and run it again. Section 3 explains what you should see.

Memory hook: and needs both; or needs either; not flips one.

3. Work out a mixed condition in Python's order

A recipe that says "add salt or pepper and lemon" leaves you guessing: is the lemon always in, or only with the pepper? Python never guesses. It has a fixed order for its logical operators, the same way it has a fixed order for arithmetic.

The order, from first to last, is not, then and, then or. All three come after the comparison operators, which come after the arithmetic, so in a line such as has_pass and bikes_free > 0 the comparison bikes_free > 0 is worked out before the and.

Worked example — and before or. Read this line from left to right and you will probably predict False. Predict it in Python's order instead.

print(True or False and False)

Output

True

Python works out the and first: False and False is False. That leaves True or False, which is True. In words: the and is grouped before the or, so the line means True or (False and False).

Worked example — not before or. The compound expression not a or b looks as if not might apply to everything after it. It does not. Run it over the four rows.

for a in (True, False):
    for b in (True, False):
        print(a, b, not a or b)

Output

True True True
True False False
False True True
False False True

The last column reads True, False, True, True. That is exactly what (not a) or b gives: on the second row, not True is False, and False or False is False. If not had flipped the whole of a or b, the second row would have been False as well, but the first row would have been False too, and it is not. In words: not grabs only the value right next to it.

Parentheses change the order, the same way they do in arithmetic. print(not (3 > 2)) works out 3 > 2 first, which is True, then not True, and prints False.

Misconception check. Students often think and and or are read left to right, like a sentence, so they predict True or False and False is False. That is tempting, because English is read that way. But Python's priority is not, then and, then or. The cure is to circle the and first, work it out, and only then do the or; and when you are unsure, add parentheses that say what you mean and run both versions.

A second trap hides in the parentheses example. Students sometimes predict not (3 > 2) is True, because they see the True inside and forget the not outside. Work inside out: 3 > 2 is True, so not (3 > 2) is False.

In practice (your tools). In your browser runner, run print(True or False and False) and then print((True or False) and False). The parentheses move the or first, and the second line prints False. Seeing both outputs side by side is the quickest way to feel the priority.

Memory hook: not, then and, then or; parentheses beat them all.

4. Choose which code runs: if, elif, and else

A traffic light at a crossing works through its questions in order. Is the button pressed? Then stop the cars. Otherwise, has the green phase run long enough? Then change. Otherwise, stay green. The light never does two of these at once, and it always asks the first question first.

Python's tool for this is the if statement, a statement that runs its indented block only when its condition is True, and may carry elif and else branches below it.

A few more words name the parts:

  • A condition is the Boolean expression after if or elif that Python tests to decide whether that branch's block runs.
  • A branch is one of the alternative blocks of code in an if statement; Python runs at most one branch each time the statement runs.
  • elif is a further test in an if statement, short for else if, that Python checks only when every test above it was False.
  • else is the last branch of an if statement, with no condition of its own, which runs only when every test above it was False.
  • A block is the lines indented four spaces under an if, elif, or else line, which run together as that branch's code.

Every if, elif, and else line ends with a colon, and the block under it is indented four spaces. The indentation is not decoration; it is how Python knows which lines belong to which branch.

Worked example — a thermostat with two branches. The room reads 17 degrees and the setting is 18.

temperature = 17
if temperature < 18:
    print("Heat on")
else:
    print("Heat off")

Output

Heat on

The condition temperature < 18 is 17 < 18, which is True, so the block under if runs and prints Heat on. The else block is skipped. In words: exactly one of the two messages prints, and the condition decided which one.

Worked example — the reading log picks one of three messages. This is the reading log's Week 4 stage. It asks whether you have met your goal, then whether you are at least halfway, and otherwise tells you to keep going. Predict the output before you read it.

goal = 300
pages_read = 45
if pages_read >= goal:
    print("Goal met")
elif pages_read >= goal // 2:
    print("Halfway or better")
else:
    print("Keep going")

Output

Keep going

Trace it one test at a time:

  1. The if test is pages_read >= goal, which is 45 >= 300. That is False, so its block is skipped.
  2. The elif test is pages_read >= goal // 2. Floor division gives goal // 2 as 150, so the test is 45 >= 150, which is also False. Its block is skipped.
  3. Every test above the else was False, so the else block runs and prints Keep going.

In words: with 45 of 300 pages read, you are not yet halfway, so the log tells you to keep going.

Now change one value. With pages_read = 150, the same program prints Halfway or better, because 150 >= 300 is False and 150 >= 150 is True. With pages_read = 300, it prints Goal met, because 300 >= 300 is True, and Python skips every test below it, even though 300 >= 150 is also True. That last case is the heart of the chapter: once a branch runs, the rest of the chain is never checked.

The reading log's Week 4 program run with three different values of pages_read, and the one message each run printed
pages_read First test true Message printed
45 none, so the else runs Keep going
150 the elif test Halfway or better
300 the if test Goal met

Worked example — a three-way chain. One more, from the pinned predict-the-output set.

x = 7
if x > 10:
    print("big")
elif x > 5:
    print("medium")
else:
    print("small")

Output

medium

The test x > 10 is 7 > 10, which is False. The test x > 5 is 7 > 5, which is True, so medium prints and the chain ends there. The else is never reached.

Misconception check. Students often read an elif chain as a list of separate if questions, each checked on its own, and expect every true branch to print. That is tempting, because each line looks like a complete question. But an elif is checked only when every test above it was False, so at most one branch runs. The cure is to trace from the top and stop at the first True.

In practice (your tools). Open Python Tutor at pythontutor.com, paste in the reading log's Week 4 program, and click the button to visualize it. Step forward one line at a time and watch the red arrow jump from the if line to the elif line to the else line, skipping the blocks it does not run. Then change pages_read to 150 and step through again.

Pause and choose one of these to think about before you read on:

  • (a) Think of a decision you make in a fixed order every morning, such as checking the weather before choosing a jacket. What would go wrong if you asked the questions in a different order?
  • (b) Think of a rule at work, at school, or in a game that has several cases, such as a price that changes with age. Which case would you have to check first so that no one lands in the wrong one?

Memory hook: test from the top; the first True wins, and the rest are skipped.

5. Find and fix the two classic conditional bugs

A form that will not submit because one box is blank is annoying, but at least it tells you something is wrong. A form that submits and quietly files your request under the wrong heading is worse, because nothing warns you. Conditionals have one bug of each kind.

Bug one: = where you meant ==. Here is a program that tries to check whether x holds 5.

x = 5
if x = 5:
    print("yes")

Output

SyntaxError

Nothing printed, not even from line 1. Python read the whole program before running any of it, found = where a condition belongs, and refused. The last line of the error message names SyntaxError, the same error type Week 1 showed for text Python cannot read. The cure is one character: write if x == 5:, and the program prints yes.

Bug two: tests in the wrong order. The second bug is quieter, and it has its own name. A logic error is a mistake that lets the program run without any error message but makes it print the wrong thing, such as tests in the wrong order.

Worked example — a letter for a number, out of order and in order. This program turns the number 95 into a letter, first with its tests in the wrong order, then with the same tests reordered.

total = 95
if total >= 60:
    print("D or better")
elif total >= 90:
    print("A")
else:
    print("F")

if total >= 90:
    print("A")
elif total >= 60:
    print("D or better")
else:
    print("F")

Output

D or better
A

In the first chain, the first test is total >= 60, and 95 passes it. That branch runs, prints D or better, and the chain ends, so the total >= 90 test is never checked. The program did exactly what was written, not what was meant. In the second chain, the strictest test comes first: 95 >= 90 is True, so it prints A.

The two bugs belong to different families, and naming the family tells you where to look:

  • A syntax error means Python could not read the text, so no line ran. Read the last line of the error message, then look at the line it points to.
  • A logic error means the program ran and printed the wrong thing. There is no error message, so you find it by predicting the output, running the program, and comparing.

Misconception check. Students often think the order of the elif tests does not matter, as long as every test is correct on its own. That is tempting, because each test in the first chain is a true statement about 95. But only the first true branch runs, so a loose test placed early swallows every value a stricter test below it was meant to catch. The cure is to order range tests from the strictest to the loosest, and then test the program with a value from each range.

In practice (your tools). Type the out-of-order chain into your browser runner and run it with 95, then with 75 and 40, writing your prediction down each time. Then swap the first two tests, run all three values again, and check that each value now lands in the branch you meant.

Memory hook: a syntax error stops the run; a logic error runs and lies.

6. Check truthiness and a chatbot's claim with a run

A sign-up form often treats an empty box as "nothing entered" and any filled box as "something entered", whatever is typed in it. Python does something similar: every value, not only True and False, counts as one or the other when it is used as a condition.

  • truthy — Describes a value that bool() turns into True when it is used as a condition, such as any string with at least one character.
  • falsy — Describes a value that bool() turns into False when it is used as a condition, such as the empty string or the number 0.

Worked example — the empty string and the string "0". Predict both values before you run the line.

print(bool(""), bool("0"))

Output

False True

The empty string "" has no characters, so it is falsy and bool("") prints False. The string "0" has one character in it, the digit zero, so it is truthy and bool("0") prints True. In words: for a string, only emptiness counts as false; the characters inside do not matter.

Caveat: this course keeps truthiness light. You need to recognize that 0 and "" are falsy, so that a condition such as if name: makes sense when you meet it. You do not need to write conditions that lean on truthiness this week; a plain comparison such as len(name) > 0 says the same thing more plainly.

Worked example — checking a chatbot's claim. Suppose you ask a chatbot what print(True or False and False) displays. It answers False, explaining that Python reads left to right: True or False is True, and True and False is False. That sounds reasonable. Run it.

print(True or False and False)

Output

True

The run printed True. The chatbot's explanation contradicts what the code prints, because it ignored the priority not, then and, then or. You caught it the only reliable way: by running the code.

Misconception check. Students often think 0 and "" are not Booleans, so they cannot be used in a condition at all. They are not of type bool, but Python still treats them as false when a condition needs a yes-or-no answer, which is what "falsy" means. The cure is to ask bool() whenever you are unsure how a value will be read.

In practice (your tools). Ask your approved chatbot to predict bool("False") and bool(" "), a string holding one space. Write its answers down, then run both in your browser runner. The if statement is described in the Python Tutorial, section 4.1, on docs.python.org.

Honesty note: decisions are a bigger subject than one chapter. This chapter covers one level of if, elif, and else; nesting one if inside another and repeating a decision in a loop come in later weeks.

Memory hook: the chatbot proposes; the run decides.

Key terms

  • Boolean expression — An expression that Python works out to one of the two bool values, True or False, such as pages_read >= goal. (first used: 1. Ask a yes-or-no question: comparison operators)
  • comparison operator — One of the six operators ==, !=, <, >, <=, and >= that compare two values and give True or False. (first used: 1. Ask a yes-or-no question: comparison operators)
  • equality operator — The == operator, which asks whether two values are equal and gives True or False, unlike =, which gives a name a value. (first used: 1. Ask a yes-or-no question: comparison operators)
  • logical operator — One of the three words and, or, and not, which combine or flip Boolean values to build a bigger condition. (first used: 2. Combine questions: and, or, not, and truth tables)
  • and — The logical operator that gives True only when the conditions on both of its sides are True. (first used: 2. Combine questions: and, or, not, and truth tables)
  • or — The logical operator that gives True when at least one of its sides is True, and False only when both sides are False. (first used: 2. Combine questions: and, or, not, and truth tables)
  • not — The logical operator that flips one Boolean value, so not True is False and not False is True. (first used: 2. Combine questions: and, or, not, and truth tables)
  • truth table — A table that lists every combination of True and False for its inputs, one row each, beside the value an expression gives on that row. (first used: 2. Combine questions: and, or, not, and truth tables)
  • if statement — A statement that runs its indented block only when its condition is True, and may carry elif and else branches below it. (first used: 4. Choose which code runs: if, elif, and else)
  • condition — The Boolean expression after if or elif that Python tests to decide whether that branch's block runs. (first used: 4. Choose which code runs: if, elif, and else)
  • branch — One of the alternative blocks of code in an if statement; Python runs at most one branch each time the statement runs. (first used: 4. Choose which code runs: if, elif, and else)
  • elif — A further test in an if statement, short for else if, that Python checks only when every test above it was False. (first used: 4. Choose which code runs: if, elif, and else)
  • else — The last branch of an if statement, with no condition of its own, which runs only when every test above it was False. (first used: 4. Choose which code runs: if, elif, and else)
  • block — The lines indented four spaces under an if, elif, or else line, which run together as that branch's code. (first used: 4. Choose which code runs: if, elif, and else)
  • logic error — A mistake that lets the program run without any error message but makes it print the wrong thing, such as tests in the wrong order. (first used: 5. Find and fix the two classic conditional bugs)
  • truthy — Describes a value that bool() turns into True when it is used as a condition, such as any string with at least one character. (first used: 6. Check truthiness and a chatbot's claim with a run)
  • falsy — Describes a value that bool() turns into False when it is used as a condition, such as the empty string or the number 0. (first used: 6. Check truthiness and a chatbot's claim with a run)

Summary

  • A comparison such as pages_read >= goal gives a bool, True or False, and changes no value.
  • = gives a name a value; == asks whether two values are equal.
  • and is True only when both sides are True; or is False only when both sides are False; not flips one value.
  • Python works out not, then and, then or; parentheses go first of all.
  • An if, elif, and else chain runs only its first true branch, so the order of the tests is part of the program.
  • = in a condition is a SyntaxError; tests in the wrong order are a logic error.
  • The empty string and 0 are falsy; any string with a character in it is truthy.

Check your understanding

Work these before looking at the answers — they are ungraded, and the answers (with reasoning) are at the bottom of the page.

  1. A cinema app checks a showing with print(12 > 9 and 4 > 7) (an illustrative example). Predict what it displays, and say which part decides it.
  2. A parking garage sets hours = 3 and then runs an if statement: if hours > 4: prints Day rate, elif hours > 1: prints Hourly rate, and else: prints Free. Predict the output and say why the other two messages do not print.
  3. A game program contains the line if level = 2:. What happens when you press Run, how many lines print, and what is the one-character fix?
  4. Predict what print(not False and False) displays, working in Python's order.

Answers (worked reasoning — read after attempting)

  1. It prints False. The left side, 12 > 9, is True, but the right side, 4 > 7, is False. With and, both sides must be True, so the one False side decides it.
  2. It prints Hourly rate. The first test, hours > 4, is 3 > 4, which is False, so Day rate is skipped. The elif test, hours > 1, is 3 > 1, which is True, so Hourly rate prints and the chain stops. The else never runs, because a branch above it already ran.
  3. Python refuses to run the program at all, so no lines print, and the last line of the error message names SyntaxError. The = gives a name a value and cannot sit where a condition belongs. The fix is if level == 2:, which asks whether level is equal to 2.
  4. It prints False. The not goes first and applies only to the value right next to it: not False is True. Then the and: True and False is False. If you read it as not (False and False), you would get True, which is the misconception this item was built to catch.

Next up in this module: the lecture, the Readings & Resources page, the lecture tutorial, the practice set, and the quiz — and next week, the while loop repeats a block for as long as its test stays True.

Built with The Course Maker · samples.thecoursemaker.com