Boolean Expressions, Comparisons, and Truthiness
Key Takeaways
- Python boolean literals are exactly True and False; lowercase true or false are undefined names that raise NameError.
- Comparison expressions produce boolean results, and chained comparisons such as 1 < x < 10 evaluate as a single combined test that touches x only once.
- Logical operators have a fixed precedence: not before and, and and before or.
- Python treats False, None, numeric zero, and empty collections or strings as falsey; every other value is truthy.
- Control Flow is the largest PCEP-30-02 domain (about 29% of the 30 questions), and boolean traps hide in truthiness, chaining, short-circuiting, and == versus is.
Why this matters on PCEP-30-02
The PCEP-30-02 (Certified Entry-Level Python Programmer) exam has 30 questions, a 40-minute limit, and a 70% passing score, delivered online through the OpenEDG Testing Service. The single-shot voucher is currently 59 USD. The Control Flow domain is the heaviest weighting on the blueprint at roughly 29%, so mastering boolean logic is the single highest-yield study target. Almost every conditional and loop question begins with an expression that must be reduced to True or False.
Boolean values and comparison operators
Python has exactly two boolean values: True and False, and capitalization is significant. true, false, and TRUE are ordinary names; using one without prior assignment raises NameError. PCEP loves this because beginners recall the concept but not Python's exact spelling.
Comparison operators always evaluate to a boolean:
| Operator | Meaning | Example | Result |
|---|---|---|---|
== | equal value | 70 == 70 | True |
!= | not equal value | 'Ana' != 'ana' | True |
< | less than | 3 < 5 | True |
<= | less than or equal | 5 <= 5 | True |
> | greater than | 2 > 9 | False |
>= | greater than or equal | 9 >= 9 | True |
A frequent trap is assignment versus comparison. The single = assigns and cannot appear as a condition: if x = 3: is a SyntaxError. Equality always uses the double ==.
Chained comparisons
Python supports chained comparisons, so 1 < x < 10 means 1 < x and x < 10, except that x is evaluated only once. Trace each link left to right; if every link is true the chain is true, and the first false link makes the whole chain false.
x = 7
print(1 < x < 10) # True
print(1 < x > 10) # False (7 > 10 fails)
print(1 == x == 7) # False (1 == 7 fails)
Logical operators and precedence
The logical operators are not, and, and or, with precedence in that order:
not(highest)andor(lowest)
So not a or b and c is read as (not a) or (b and c). Exam snippets omit parentheses on purpose to test precedence.
Python also short-circuits. For and, if the left operand is falsey, the right side is never evaluated and the left operand is returned. For or, if the left operand is truthy, that operand is returned without touching the right side. A subtle PCEP point is that and/or return one of the operands, not necessarily True/False: 0 or 'hi' evaluates to 'hi', and 5 and 0 evaluates to 0.
Truthiness
Conditions need not be explicit comparisons; Python tests the truth value of objects directly:
| Value | Truth value |
|---|---|
False, None | falsey |
0, 0.0 | falsey |
'', [], {}, () | falsey |
| nonzero numbers | truthy |
| nonempty strings/collections | truthy |
Do not confuse the string 'False' with the boolean False: the string is nonempty, so it is truthy. Likewise '0' is truthy because the character zero is still a nonempty string.
Identity versus equality
== compares values; is compares identity (the same object in memory). For small integers and short strings CPython may cache objects so a is b happens to match a == b, but PCEP wants you to know they are conceptually different. Use is only with None: if x is None:.
Trace-table method
Never solve a boolean expression in your head all at once. Build a tiny table.
| Step | Expression part | Value | Result |
|---|---|---|---|
| 1 | x > 3 | 7 > 3 | True |
| 2 | name | 'Py' | truthy |
| 3 | x > 3 and name | True and truthy | truthy |
Common traps: an empty string swapped for a nonempty one; or where you expected and; a boundary < instead of <=; and assuming and/or always return literal True/False.
Boolean coercion with bool()
The built-in bool() reports the truth value of any object, which is exactly the value a condition would test. PCEP frequently shows print(bool(...)) and expects you to apply the truthiness rules.
print(bool(0)) # False
print(bool(-3)) # True (any nonzero number)
print(bool('')) # False
print(bool(' ')) # True (a space is nonempty)
print(bool([])) # False
print(bool([0])) # True (the list has one element)
print(bool(None)) # False
The trap in the last list is that [0] is truthy even though its only element is the falsey 0: truthiness of a container depends on whether it is empty, not on what it contains.
not always returns a real boolean
Unlike and and or, the not operator always returns True or False, never an operand. not 0 is True, not 'hi' is False, and not [] is True. So if a question multiplies or adds a not result, treat it as 1 or 0: True + True equals 2 because booleans are a subtype of int.
print(not 0) # True
print(not 'data') # False
print(True + True) # 2
print(False * 10) # 0
Combining comparisons with truthiness
Real exam items mix explicit comparisons and bare truthiness inside one expression. Reduce each piece to a boolean, then apply precedence.
name = 'Ann'
age = 0
if name and age > 5:
print('ok')
else:
print('no')
This prints no. The left operand name is truthy, so and evaluates the right operand age > 5, which is 0 > 5, that is False; truthy and False is False.
A precedence checklist for exam day
| Question feature | What to check |
|---|---|
Mixed not/and/or | Apply not, then and, then or |
| Bare variable in a condition | Decide truthy or falsey, do not assume a comparison |
== near is | == is value, is is identity (use is with None) |
| Chained comparison | Split into and-joined links, evaluate left to right |
and/or result reused | Return value is an operand, not necessarily True/False |
not result reused arithmetically | Treat as integer 1 (True) or 0 (False) |
Work the table top to bottom on any boolean snippet and you will resolve almost every PCEP-30-02 boolean item without guessing.
What is printed by this code? x = 4 print(1 < x < 4 or x == 4)
What value does the expression 0 or 'hi' produce?
Which value is truthy in a Python condition?
How is this expression grouped by Python's operator precedence? not a or b and c