The simplest control structure, with a couple of catches
Branching in Python looks like the branching you've seen elsewhere — if, elif, else — but two things make it specifically Pythonic. First, the condition isn't required to be a boolean: any object has a truthiness, and the language uses it. Second, you almost never write if x == True; you write if x and let the language do the right thing.
Truthiness — the rules every container follows
Empty containers are falsy. None is falsy. Zero (in any numeric type) is falsy. Empty strings are falsy. Everything else (by default) is truthy. So if my_list: means "if my_list is non-empty" and reads cleanly. if user is not None: is for the case where you specifically want to distinguish None from an empty container — there's a real difference between "no user" and "a user with no friends."
The conditional expression — "ternary" the Python way
Other languages have condition ? a : b. Python has a if condition else b. The English-order grammar is intentional. Use it for short value selections; don't nest more than one. The moment you find yourself writing (a if c1 else b) if c2 else (c if c3 else d), you've passed the readability point — write a real if.
Principle: Don't compare with == True or == False. if flag: and if not flag: are clearer and don't introduce subtle bugs when the value is something other than a strict boolean.
Chained comparisons — the syntax you may not know exists
Python allows 1 < x < 10 as a single expression. It evaluates as (1 < x) and (x < 10) but only computes x once. Useful for range checks, age bounds, anywhere two comparisons would be paired. Most languages don't have this, so it surprises engineers coming from C/Java.
Pythonic Way: If your if/elif chain has more than four or five branches and they're all looking up keyed values, consider a dict instead. handlers = {"a": fn_a, "b": fn_b} + handlers[key](). The Python 3.10 match statement is also there if structural matching is what you want — and that's the next lesson.
Code
Truthiness — the rules in code·python
# Falsy values
for x in [None, False, 0, 0.0, "", [], {}, set(), ()]:
if x:
print("truthy")
else:
print("falsy")
# All print 'falsy'
# Idiomatic empty check
items = []
if items: # vs. if len(items) > 0:
print("have items")
else:
print("empty") # this prints
# But — None and empty are NOT the same
user = None
if user is None:
print("no user at all")
elif not user:
print("user exists but is empty")
else:
print("user with content")
Conditional expression — the Python ternary·python
n = 7
label = "odd" if n % 2 else "even"
print(label) # 'odd'
# Common: default value selection
user_input = ""
name = user_input or "anonymous"
print(name) # 'anonymous'
# `or` returns the FIRST truthy value, not necessarily True
print(0 or 5 or 99) # 5
print([] or [1]) # [1]
# `and` returns the FIRST falsy value, or the last value
print(1 and 2 and 3) # 3
print(1 and 0 and 3) # 0 (short-circuit)
Chained comparisons — Python's special·python
x = 5
# Chained — Python only
if 1 < x < 10:
print("in range")
# Equivalent to
if 1 < x and x < 10:
print("same idea")
# But — x is only evaluated once
def get_x():
print("computing x")
return 5
if 1 < get_x() < 10:
print("computed once")
# 'computing x' prints ONCE
Don't compare with == True / == False·python
active = True
# DON'T
if active == True:
pass
# DO
if active:
pass
# More importantly — this saves you when active is something
# that's truthy but isn't literally True
active = 1 # int 1, not bool True
if active == True: # True (because 1 == True is True)
print("compares")
active = "yes"
if active == True: # False
print("this won't print")
if active: # truthy
print("this prints")
Write a function classify(score) that returns: "perfect" if score is 100, "pass" if 70 <= score < 100, "retry" if 0 <= score < 70, and "invalid" for anything else (negative, > 100, None, or non-numeric). Use chained comparisons where they help, the conditional expression somewhere, and if x is None for the None case explicitly. Test with at least 6 inputs.
Progress
Progress is local-only — sign in to sync across devices.