Conditional statements let your program make decisions — executing different code depending on whether a condition is true or false. Python’s conditional syntax is cleaner than most languages: no parentheses required around the condition, no curly braces, and a colon at the end of each clause. The if, elif, and else keywords are Python’s only conditional statement — there is no switch or case statement in Python (though match was added in Python 3.10 as a structural pattern matching tool). You will use conditionals constantly in FastAPI: checking authentication status, validating request data, and deciding which database query to run.
Basic if / elif / else
# Syntax: condition followed by colon, body is indented
age = 25
if age >= 18:
print("Adult")
# if / else
if age >= 18:
print("Adult")
else:
print("Minor")
# if / elif / else — multiple conditions checked in order
score = 75
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
elif score >= 70:
grade = "C"
elif score >= 60:
grade = "D"
else:
grade = "F"
print(f"Grade: {grade}") # Grade: C
# Only the FIRST matching branch runs — the rest are skipped
# Once a condition is True, Python does not check further elif/else
if, elif, and else line, and the body must be indented by exactly 4 spaces (or a consistent number of spaces/tabs — but 4 spaces is the PEP 8 standard). Forgetting the colon is the single most common syntax error for new Python developers. Your code editor should highlight this immediately, but it is worth memorising: every control flow header line ends with a colon.if is_active == True:, write if is_active:. Instead of if name != "":, write if name: (truthy if non-empty). This is idiomatic Python and what you will see in FastAPI and SQLAlchemy source code. However, always use is None and is not None when checking for None — never rely on truthiness for None checks.switch statement — use if/elif/else chains instead. If you have many branches based on a single value, consider a dictionary dispatch pattern (covered in Chapter 5) which is more Pythonic and faster for large numbers of cases. Python 3.10 introduced the match statement for structural pattern matching, but if/elif/else remains the standard for simple value comparisons.Conditions and Truthiness
# Truthy values — evaluate to True in a boolean context
if 42: print("non-zero int is truthy")
if 3.14: print("non-zero float is truthy")
if "hello": print("non-empty string is truthy")
if [1, 2, 3]: print("non-empty list is truthy")
if {"a": 1}: print("non-empty dict is truthy")
# Falsy values — evaluate to False
if not 0: print("0 is falsy")
if not 0.0: print("0.0 is falsy")
if not "": print("empty string is falsy")
if not []: print("empty list is falsy")
if not {}: print("empty dict is falsy")
if not None: print("None is falsy")
if not False: print("False is falsy")
# Practical FastAPI examples
def get_post(post_id: int):
post = db.get_post(post_id) # returns None if not found
if post is None: # explicit None check — always use 'is'
raise HTTPException(404)
if not post.published: # truthy check — published is bool
raise HTTPException(403)
return post
def search_posts(query: str):
if not query: # checks for empty string or None
return [] # no query — return empty list
return db.search(query)
The Ternary Expression
# Python ternary: VALUE_IF_TRUE if CONDITION else VALUE_IF_FALSE
# Note the order is different from JavaScript: condition ? true : false
age = 20
status = "adult" if age >= 18 else "minor"
print(status) # "adult"
# JavaScript equivalent: age >= 18 ? "adult" : "minor"
# Practical uses
user_name = user.name if user else "Guest"
page_size = limit if limit <= 100 else 100
label = f"{count} item" if count == 1 else f"{count} items"
# Avoid nesting ternaries — hard to read
# Bad:
result = "a" if x > 0 else "b" if x < 0 else "c" # confusing
# Better: use if/elif/else for three or more branches
Nested Conditions and Combining
# Nested conditions — indent each level
role = "admin"
is_active = True
if role == "admin":
if is_active:
print("Active admin — full access")
else:
print("Inactive admin — no access")
else:
print("Regular user")
# Equivalent using 'and' — often cleaner
if role == "admin" and is_active:
print("Active admin — full access")
# Checking membership
ALLOWED_ROLES = {"user", "editor", "admin"} # set — O(1) lookup
if role in ALLOWED_ROLES:
print(f"Role '{role}' is valid")
# FastAPI guard clause pattern — return early on failure
def update_post(post_id: int, user_id: int):
post = db.get(post_id)
if post is None:
raise HTTPException(404, "Post not found")
if post.author_id != user_id:
raise HTTPException(403, "Not authorised")
# Only reach here if post exists and user is the owner
return db.update(post_id)
Common Mistakes
Mistake 1 — Missing the colon
❌ Wrong — colon missing after condition:
if age >= 18
print("Adult") # SyntaxError: expected ':'
✅ Correct — colon is required on every header line:
if age >= 18:
print("Adult") # ✓
Mistake 2 — Wrong indentation level
❌ Wrong — body not indented or inconsistently indented:
if age >= 18:
print("Adult") # IndentationError — body must be indented
if age >= 18:
print("Check 1")
print("Check 2") # IndentationError — inconsistent indent
✅ Correct — consistent 4-space indent for the body:
if age >= 18:
print("Check 1") # ✓ 4 spaces
print("Check 2") # ✓ same level
Mistake 3 — Using == True instead of truthiness
❌ Wrong — verbose comparison to True:
if is_active == True: # works but un-Pythonic
...
✅ Correct — use truthiness directly:
if is_active: # ✓ idiomatic Python
...
Quick Reference
| Pattern | Code |
|---|---|
| Simple if | if condition: |
| if/else | if condition: ... else: ... |
| if/elif/else | if c1: ... elif c2: ... else: ... |
| Ternary | value_a if condition else value_b |
| Membership check | if item in collection: |
| None check | if value is None: |
| Truthiness check | if value: (non-empty, non-zero, not None) |
| Negative truthiness | if not value: |