Skip to content
Lesson 7 of 13

Step 1 of 8 · Reading · ~4 min

Learn

Making Decisions

Combining Conditions

You already know and, or and not on their own. This lesson is about what happens when three or four of them meet in one expression: which operator binds tightest, where parentheses change the answer, and how to convince yourself a compound condition is right before you trust it.

Precedence: not, then and, then or

An expression without parentheses is not evaluated left to right. Python groups it for you, tightest operator first: not, then and, then or.

python

Same three values, two different answers. The first line is read as is_member or (is_guest_day and gym_open), which says "a member always gets in, open or not". The second says "the building has to be open for anybody". One of those is the rule you meant, and Python cannot tell which. Whenever and and or appear in the same expression, write the parentheses, even when they agree with the default grouping.

Checking a compound condition by hand

A condition over three inputs has eight possible combinations, and you can walk the interesting ones. Take can_enter = (gym_open and has_pass) or is_staff:

gym_open  has_pass  is_staff   can_enter
True      True      False      True
True      False     False      False
False     True      False      False
False     False     True       True

The last row is the one to notice: staff get in with the building shut, because or is_staff sits outside the parentheses and overrides everything to its left. If that is wrong for your building, the fix is a different grouping, not a different operator. Walking three or four rows like this catches more bugs than re-reading the expression does.

Divisibility as a condition

% gives the remainder, so n % 5 == 0 reads "n divides evenly by 5", and n % 5 != 0 is its negation.

python

Write the negative form as n % 7 != 0. The shorter not n % 7 happens to work, because 0 is falsy, but it reads backwards and hides the comparison from whoever reads it next.

De Morgan's laws

Two identities let you move a not across a group:

not (A and B)   is the same as   (not A) or  (not B)
not (A or  B)   is the same as   (not A) and (not B)

So not (is_admin or is_owner) and not is_admin and not is_owner are the same test. Pick whichever reads closer to the sentence you would say out loud.

Chained comparisons

Python lets you write a range test the way maths does:

python

That is exactly 0 <= score and score < 100, except that score is evaluated once. Chains are excellent for ranges and confusing for anything else.

Common mistakes

  • Testing the general rule and stopping there. A rule that has an exception needs both clauses. Keep only the general part and the answer is right for ordinary inputs and wrong for precisely the values the exception was written for.
  • Losing the override. When a narrow case is meant to beat an exception, it belongs in its own group, or-ed on at the top level. Bury it inside the and group and every value it exists for comes out on the wrong side.
  • if n % 3 == 0 or 5: - or does not distribute over ==. Python reads this as (n % 3 == 0) or 5, and 5 is truthy, so the condition is True for every input. Repeat the comparison: n % 3 == 0 or n % 5 == 0.
  • Grouping by accident. (A or C) and B and (A and B) or C are built from the same three tests and disagree on real inputs. Write the parentheses you mean instead of trusting the default.

Your exercise

A year arrives on input, and the starter already prints leap or not leap from a variable named is_leap that is hard-coded to False. Your job is that one assignment: replace False with a single boolean expression over year that is True for exactly the leap years. The likeliest mistake is an override that gets swallowed by a group, so check a year like 2000 as well as an ordinary one before you submit.

Up nextFor LoopsLoops and Iteration

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…