Syntax Cache
BlogMethodFeaturesHow It WorksBuild a Game
  1. Home
  2. Python
  3. Python Conditionals Practice: Truthiness, Boolean Logic, Ternary, and Comparisons
Python35 exercises

Python Conditionals Practice: Truthiness, Boolean Logic, Ternary, and Comparisons

Practice Python conditionals: truthy/falsy rules, and/or short-circuiting, operator precedence, match/case, chained comparisons, and is vs == for None.

Cheat SheetCommon ErrorsQuick ReferencePractice
Warm-up1 / 2

Can you write this from memory?

Write an if-else statement: - If active is True, print "item active" - Otherwise, print "item pending"

On this page
  1. 1The truthiness cheat sheet
  2. 2and/or don't return booleans
  3. 3is vs ==: identity vs equality
  4. 4The if x trap
  5. 5Operator precedence
  6. 6Chained comparisons
  7. 7Guard clauses: early return pattern
  8. 8any() and all(): readable aggregate checks
  9. 9Ternary expressions
  10. 10Comparing to True/False
  11. 11match/case: Python's switch statement (3.10+)
  12. Pattern matching power
  13. 12The walrus operator (:=): check and capture
  14. 13Common patterns
  15. Default with None-check
  16. Conditional in comprehension
  17. 14References
The truthiness cheat sheetand/or don't return booleansis vs ==: identity vs equalityThe if x trapOperator precedenceChained comparisonsGuard clauses: early return patternany() and all(): readable aggregate checksTernary expressionsComparing to True/Falsematch/case: Python's switch statement (3.10+)The walrus operator (:=): check and captureCommon patternsReferences

Python's if/else looks trivial... until a valid value like 0 gets treated as "missing", you accidentally rely on operator precedence, or you compare to None the wrong way.

The exercises here focus on the rules that quietly create bugs:

  • truthy/falsy categories (empty containers, zero numerics, None)
  • boolean operators that short-circuit and return operands (and/or)
  • operator precedence (not > and > or)
  • chained comparisons (0 < x < 10)
  • identity vs equality (is vs ==)
Related Python Topics
Python Loops: range(), enumerate(), zip(), break/continue, for-elsePython Function Arguments: defaults, *args, keyword-only, **kwargsPython Collections: Lists, Dicts, Sets & Tuples

Three falsy buckets: None/False, zero numerics (0, 0.0, 0j), and empty collections ("", [], {}, set()). Everything else is truthy.

Python's falsy values fall into three buckets:

CategoryFalsy values
ConstantsNone, False
Zero numerics0, 0.0, 0j, Decimal(0), Fraction(0, 1)
Empty collections"", (), [], {}, set(), range(0)

Everything else is truthy (including "0", "False", [0], etc.).


Ready to practice?

Start practicing Python Conditionals: Truthiness, Boolean Logic, Ternary, and Comparisons with spaced repetition

and/or return operands, not True/False. The x or default pattern is dangerous when 0, "", or [] are valid values—use an explicit None check instead.

This catches people off guard. Python's boolean operators return one of their operands, not True/False:

# and: returns first falsy value, or last value if all truthy
0 and "hello"     # → 0 (stopped at first falsy)
"hi" and "hello"  # → "hello" (all truthy, returns last)

# or: returns first truthy value, or last value if all falsy
0 or "default"    # → "default" (found truthy)
"hi" or "hello"   # → "hi" (stopped at first truthy)
None or 0 or ""   # → "" (all falsy, returns last)

Why this matters: The x or default pattern is dangerous when 0, "", or [] are valid values:

# BUG: user_count of 0 gets replaced with 1
user_count = provided_count or 1

# FIX: explicit None check
user_count = provided_count if provided_count is not None else 1

Use is for singletons (None, True, False). Use == for comparing values. PEP 8 requires None comparisons use is, not ==.

OperatorWhat it checksUse for
isSame object in memoryNone, True, False (singletons)
==Values are equalEverything else
# Correct: is for None
if value is None:
    return "missing"

# Wrong: == can be overridden by __eq__
if value == None:  # works, but PEP 8 discourages
    return "missing"

PEP 8: "Comparisons to singletons like None should always be done with is or is not, never the equality operators."


if x tests truthiness, not existence. This is often fine, but breaks when falsy values are valid:

# BUG: treats 0 and "" as "missing"
def get_value(x):
    if x:
        return x
    return "default"

get_value(0)   # → "default" (wrong!)
get_value("")  # → "default" (wrong!)

# FIX: be explicit about what you're checking
def get_value(x):
    if x is not None:
        return x
    return "default"

Rule of thumb: If 0, "", [], or False are valid inputs, don't use if x. This is especially important when writing Python functions with optional parameters that could legitimately be zero or empty.


not binds tighter than and, which binds tighter than or:

not a and b or c
# Is parsed as:
((not a) and b) or c

Best practice: Use parentheses whenever precedence isn't obvious at a glance.

# Hard to parse
if not is_admin and is_premium or is_trial:
    ...

# Clear
if (not is_admin and is_premium) or is_trial:
    ...

Python allows comparison chaining—it's not just syntactic sugar:

# These are equivalent:
if 0 < x < 100:
    print("in range")

if 0 < x and x < 100:
    print("in range")

But with chained comparisons, x is evaluated only once. This matters when x is a function call:

# get_value() called once
if 0 < get_value() < 100:
    ...

# get_value() called twice
if 0 < get_value() and get_value() < 100:
    ...

Instead of deep nesting, return early for invalid cases:

# Nested (harder to read)
def process(data):
    if data is not None:
        if data.is_valid:
            if data.has_permission:
                return do_work(data)
    return None

# Guard clauses (clearer)
def process(data):
    if data is None:
        return None
    if not data.is_valid:
        return None
    if not data.has_permission:
        return None
    return do_work(data)

When checking if any/all items match a condition, use any()/all() instead of loops:

# Instead of:
has_negative = False
for x in nums:
    if x < 0:
        has_negative = True
        break

# Use:
has_negative = any(x < 0 for x in nums)

# Instead of:
all_positive = True
for x in nums:
    if x <= 0:
        all_positive = False
        break

# Use:
all_positive = all(x > 0 for x in nums)

Both short-circuit (stop as soon as the answer is known). You'll see these frequently in loop conditions and comprehension filters.


For simple conditional assignments, ternary is cleaner:

# Instead of:
if condition:
    result = value_if_true
else:
    result = value_if_false

# Use:
result = value_if_true if condition else value_if_false

Avoid nested ternaries—they're hard to read:

# Don't do this
grade = "A" if score >= 90 else "B" if score >= 80 else "C" if score >= 70 else "F"

# Use if/elif/else instead

Usually unnecessary and can break with truthy/falsy values:

# Redundant
if is_valid == True:
    ...

# Preferred
if is_valid:
    ...

# Exception: when you need to distinguish True from other truthy values
if flag is True:  # only matches True, not 1 or "yes"
    ...

For complex branching based on value or structure, match is cleaner than if/elif chains:

# if/elif chain
def http_status(code):
    if code == 200:
        return "OK"
    elif code == 404:
        return "Not Found"
    elif code == 500:
        return "Server Error"
    else:
        return "Unknown"

# match/case (cleaner)
def http_status(code):
    match code:
        case 200:
            return "OK"
        case 404:
            return "Not Found"
        case 500:
            return "Server Error"
        case _:
            return "Unknown"

Pattern matching power

match does more than simple value comparison—it can destructure and match structure:

# Match multiple values
match code:
    case 200 | 201 | 204:
        return "Success"
    case 400 | 401 | 403 | 404:
        return "Client Error"

# Destructure sequences
match point:
    case (0, 0):
        return "origin"
    case (x, 0):
        return f"on x-axis at {x}"
    case (0, y):
        return f"on y-axis at {y}"
    case (x, y):
        return f"at ({x}, {y})"

# Match with guards
match user:
    case {"role": "admin"}:
        return "full access"
    case {"role": "user", "verified": True}:
        return "standard access"
    case {"role": "user", "verified": False}:
        return "limited access"

# Class matching
match event:
    case Click(x, y) if x < 0 or y < 0:
        return "out of bounds"
    case Click(x, y):
        return f"clicked at ({x}, {y})"
    case KeyPress(key="enter"):
        return "submitted"

When to use match vs if/elif:

  • Use match when checking against multiple discrete values or patterns
  • Use if/elif for range checks, complex boolean logic, or Python < 3.10

The walrus operator (Python 3.8+) assigns and returns a value in one expression. It's perfect for "check if exists, then use" patterns:

# Without walrus: call function twice or use temp variable
result = expensive_operation()
if result:
    use(result)

# With walrus: assign and check in one step
if (result := expensive_operation()):
    use(result)

# Great for regex matching
if (match := pattern.search(text)):
    print(f"Found: {match.group()}")

# Useful in comprehensions (filter + use computed value)
results = [y for x in data if (y := transform(x)) is not None]

Default with None-check

# When 0/""/[] are valid values
value = provided if provided is not None else default

# When you only want to replace None
config.get("timeout") or 30  # BUG if timeout=0 is valid
config.get("timeout", 30)    # Better: use dict.get default

Conditional in comprehension

Conditionals are central to Python collections work, especially filtering and transforming data:

# Filter (if at end excludes items)
positives = [x for x in nums if x > 0]

# Transform (if-else at start transforms all)
labels = ["pos" if x > 0 else "non-pos" for x in nums]

  • Truth Value Testing — falsy categories, __bool__
  • Boolean Operations — and/or short-circuit, return operands
  • Comparisons — chained comparisons, is/is not
  • match Statement — structural pattern matching (3.10+)
  • PEP 634 — match/case specification
  • PEP 8: Programming Recommendations — None checks, avoiding == True/False

When to Use Python Conditionals: Truthiness, Boolean Logic, Ternary, and Comparisons

  • Branch on state, validation, or feature flags.
  • Use guard clauses (early return) to keep functions readable.
  • Use ternaries for short, expression-level choices.
  • Use `any()` / `all()` when your intent is "any match" or "all pass".

Check Your Understanding: Python Conditionals: Truthiness, Boolean Logic, Ternary, and Comparisons

Prompt

Given an optional score (may be None), return "pass" if score >= 70 else "fail".

What a strong answer looks like

Handle None explicitly (identity check), then compare: `if score is None: return "fail"` (or raise); otherwise `score >= 70`. Mention why `is None` is preferred and why `if score` would be wrong if score can be 0.

What You'll Practice: Python Conditionals: Truthiness, Boolean Logic, Ternary, and Comparisons

if/elif/else chainsmatch/case structural pattern matching (3.10+)Guard clauses (early return)Boolean operators (and, or, not) + short-circuitingOperator precedence (not > and > or)Comparison operators + chained comparisonsIdentity vs equality (is vs ==)Membership testing (in, not in)Walrus operator (:=) for check-and-captureUsing any() / all() for readable conditions

Common Python Conditionals: Truthiness, Boolean Logic, Ternary, and Comparisons Pitfalls

  • Using `if x` when you really mean `if x is not None` (because 0/""/[] are falsy)
  • Using `x or default` when 0/"" are valid values (you may accidentally replace them)
  • Assuming `and/or` return booleans (they return operands)
  • Relying on precedence in complex expressions instead of using parentheses
  • Comparing to None with `==` instead of `is`
  • Comparing booleans to True/False using `==`

Python Conditionals: Truthiness, Boolean Logic, Ternary, and Comparisons FAQ

What counts as falsy in Python?

Three buckets: (1) None and False, (2) zero of any numeric type (0, 0.0, 0j, Decimal(0), Fraction(0,1)), (3) empty sequences/collections like "", (), [], {}, set(), range(0). Everything else is truthy by default.

Should I write `x is None` or `x == None`?

Use `is None` / `is not None`. PEP 8 recommends identity comparisons for singletons like None, and warns that `if x` can be wrong when x may be an empty container or 0.

Do `and` / `or` return True/False?

No—`and`/`or` return one of their operands and short-circuit. This is useful for defaults, but it can also hide bugs when valid values are falsy (like 0 or "").

What's the precedence of not/and/or?

`not` binds tighter than `and`, which binds tighter than `or`. Use parentheses when it's not instantly obvious.

Is chained comparison allowed?

Yes: `x < y <= z` is valid and evaluates like `x < y and y <= z`, except `y` is evaluated only once (and it short-circuits).

Should I compare booleans to True/False?

Usually no—prefer `if cond:` or `if not cond:`. Comparing with `== True` is a common code smell and can break with truthy/falsy values.

Does Python have a switch statement?

Yes—`match`/`case` (Python 3.10+). It's more powerful than traditional switch: it does structural pattern matching, can destructure objects, and supports guards with `if`.

Python Conditionals: Truthiness, Boolean Logic, Ternary, and Comparisons Syntax Quick Reference

Truthy/falsy check
if not items:
    print("empty")
None check (identity)
if value is None:
    return "missing"
Safe default (don't eat 0)
name = provided if provided is not None else "Anonymous"
Ternary
result = "pass" if score >= 70 else "fail"
Chained comparisons
if 0 < x < 100:
    print("in range")
any()/all()
if any(x < 0 for x in nums):
    print("has negative")
match/case (3.10+)
match status:
    case 200: return "OK"
    case 404: return "Not Found"
    case _: return "Unknown"
Walrus operator
if (match := pattern.search(text)):
    print(match.group())

Python Conditionals: Truthiness, Boolean Logic, Ternary, and Comparisons Sample Exercises

Example 1Difficulty: 1/5

Write an if statement that executes `pass` if `True`

if True:
    pass
Example 2Difficulty: 1/5

Write an if statement that prints "Item found" if item is truthy

if item:
    print("Item found")
Example 3Difficulty: 2/5

If items is empty, print "Empty items". Use a Pythonic truthiness check (not len()).

if not items:
    print("Empty items")

+ 32 more exercises

Start practicing Python Conditionals: Truthiness, Boolean Logic, Ternary, and Comparisons

Free daily exercises with spaced repetition. No credit card required.

← Back to Python Syntax Practice
Syntax Cache

Build syntax muscle memory with spaced repetition.

Product

  • Pricing
  • Our Method
  • Daily Practice
  • Design Patterns
  • Interview Prep

Resources

  • Blog
  • Compare
  • Cheat Sheets
  • Vibe Coding
  • Muscle Memory

Languages

  • Python
  • JavaScript
  • TypeScript
  • Rust
  • SQL
  • GDScript

Legal

  • Terms
  • Privacy
  • Contact

© 2026 Syntax Cache

Cancel anytime in 2 clicks. Keep access until the end of your billing period.

No refunds for partial billing periods.