Tests are decisions in disguise. If the status code is 200, mark the case passed; else if it's 5xx, retry; else fail loudly. Python expresses those decisions with if, elif, and else — three keywords, no braces, no parentheses, and a hard rule about indentation that surprises every newcomer. This lesson covers the syntax, the comparison and logical operators, the truthy/falsy quirks, the ternary form, and in — enough conditional fluency to classify any API response or test result.
The basic shape
status_code = 200
if status_code == 200:
print("Success")
elif 400 <= status_code < 500:
print("Client error")
elif status_code >= 500:
print("Server error")
else:
print("Unknown status")Read each piece:
if condition:— the keywordif, an expression that evaluates toTrueorFalse, then a colon. The colon is mandatory; forgetting it is aSyntaxError.elif condition:— short for "else if". JavaScript and Java useelse if; Python uses one word,elif. Always check this first when porting a JS snippet.else:— runs when nothing above matched. Optional but usually a good idea so unhandled cases are visible.- The colon ends every line that opens a block.
if,elif,elseall need it.
Notice what's not there: no parentheses around the condition, no curly braces around the body. if (status_code == 200) { is JavaScript/Java; if status_code == 200: is Python.
Indentation is the syntax
The body of each branch is indented. Python uses indentation the way other languages use { }. The convention is four spaces per level — every Python tutorial, every linter, every PR review expects four. VS Code with the Python extension inserts four spaces when you press Tab.
if status_code == 200:
log_success(status_code) # 4 spaces — this line is in the if body
record_metric("response.ok") # 4 spaces — also in the if body
print("Done") # 0 spaces — this line is OUTSIDE the ifThree rules to internalise on day one:
- Be consistent within a file. Pick four spaces and stick with them.
- Don't mix tabs and spaces. Python 3 raises
TabErrorif you do. Modern editors handle this automatically — leave the defaults alone. - Indent or you've changed meaning. A line with no indent is outside the
if. The compiler in Java doesn't care if you indent; in Python the indent is whether the line belongs to the block.
Comparison operators
Same as JavaScript and Java — these all return True or False:
| Operator | Meaning | Example | Result |
|---|---|---|---|
== | Equal | 200 == 200 | True |
!= | Not equal | 200 != 404 | True |
> | Greater than | 1.5 > 1.0 | True |
< | Less than | 100 < 99 | False |
>= | Greater or equal | 200 >= 200 | True |
<= | Less or equal | 200 <= 200 | True |
Python has one nice extra — chained comparisons:
if 400 <= status_code < 500:
print("Client error")400 <= status_code < 500 is the natural reading of "is the value in this range" and is equivalent to 400 <= status_code and status_code < 500. JavaScript and Java don't have this — if (400 <= x < 500) parses but means something else there.
Logical operators — words, not symbols
This is the big break from C-family languages. Python uses English words for logical operators:
if status_code == 200 and response_time < 2000:
print("Fast success")
if status_code >= 500 or status_code == 0:
print("Server problem or no response at all")
if not is_authenticated:
print("Login required")| Python | JavaScript / Java |
|---|---|
and | && |
or | || |
not | ! |
Writing && in Python is a SyntaxError. There is no ||. Reach for the words.
Python's and and or short-circuit the same way as && / || — or stops at the first truthy value, and stops at the first falsy. Cheap left-side checks belong on the left.
Truthy and falsy values
Python evaluates non-boolean values as truthy or falsy in a boolean context (if, while, and, or):
Falsy — False, 0, 0.0, "" (empty string), [] (empty list), {} (empty dict), None.
Truthy — everything else.
results = []
if results:
print(f"{len(results)} results")
else:
print("No results yet") # this prints — empty list is falsyThat collapses what would be if (results !== null && results.length > 0) in JavaScript into just if results:. Use it carefully: if count: is False when count == 0, which is fine if zero counts as "nothing" but wrong if zero is a valid value you care about.
The ternary expression — different shape
Python's one-line conditional puts the value first, condition in the middle:
result = "PASS" if passed else "FAIL"Read it left-to-right: "result is PASS if passed else FAIL". JavaScript and Java write passed ? "PASS" : "FAIL"; Python's order is deliberately closer to English.
A QA example — labelling a response by status code:
status_code = 503
label = "ok" if status_code < 400 else "error"
print(label) # "error"Use the ternary for short, simple choices. Once you'd need parentheses to make sense of it, switch to a regular if/else block.
The in operator — membership check
in checks if a value appears inside a sequence (string, list, tuple, dict, set):
browser = "Firefox"
if browser in ["Chrome", "Firefox", "Safari"]:
print(f"{browser} is supported")
method = "POST"
if method in ("GET", "POST"):
print("Standard method")
email = "alice@test.com"
if "@" in email:
print("Looks like an email")in collapses what would be a long if x == "Chrome" or x == "Firefox" or x == "Safari" chain into a single line. not in is the negation: if browser not in supported_browsers:.
For dicts, in checks keys: if "timeout" in config:.
A QA example — classifying an API response
A function that classifies a response by its status code and latency:
def classify(status_code: int, response_time_ms: int) -> str:
if status_code == 0:
return "no-response"
if status_code >= 500:
return "server-error"
if 400 <= status_code < 500:
return "client-error"
if status_code in (200, 201, 204) and response_time_ms < 500:
return "fast-success"
if status_code in (200, 201, 204) and response_time_ms < 2000:
return "slow-success"
if status_code in (200, 201, 204):
return "very-slow-success"
return "unexpected"
print(classify(200, 320)) # "fast-success"
print(classify(503, 5000)) # "server-error"
print(classify(404, 80)) # "client-error"
print(classify(0, 0)) # "no-response"Notice how each branch returns early — once a category matches, the function exits. This pattern (a chain of if … return) reads cleanly and avoids deeply nested else ladders.
The decision tree, drawn
The chart traces the same logic the function above implements. Branches at each diamond return early; only the bottom path falls through to "unexpected."
⚠️ Common mistakes
else ifinstead ofelif.else ifis JavaScript and Java. Python rejects it as aSyntaxError. Always one word:elif.- Forgetting the colon.
if status_code == 200(no colon) raisesSyntaxError: expected ':'. Everyif,elif, andelseline ends with:. - Mixing tabs and spaces. A file that looks indented can fail with
TabError: inconsistent use of tabs and spaces. Pick four spaces and let your editor convert tabs. Most pain disappears the moment you settle this.
🎯 Practice task
Build a response-time classifier. 20-30 minutes.
- Create
classify_response.pyand define a functionclassify(status_code, response_time_ms)returning a string label. - Implement these rules with a chain of
if/elif/else:- status_code == 0 →
"no-response" - status_code >= 500 →
"server-error" - 400 ≤ status_code < 500 →
"client-error" - 2xx and response_time_ms < 500 →
"fast-success" - 2xx and 500 ≤ response_time_ms < 2000 →
"slow-success" - 2xx and response_time_ms ≥ 2000 →
"very-slow-success" - otherwise →
"unexpected"
- status_code == 0 →
- Below the function, call
classifysix times with different inputs andprinteach result. Cover at least one of each label. - Run
python classify_response.pyand confirm the output. - Add a final block: read a status code from
input(), convert withint(), classify it, and print the label. Try entering 200, 404, 503, and 0. - Stretch: add a single combined condition using
andand chained comparison:if status_code in (200, 201, 204) and 500 <= response_time_ms < 2000. Replace the two-step nested check with the single line. Confirm the behaviour is identical and the code reads more cleanly.
You can now branch on any condition Python supports. The next lesson moves on to loops — for, while, and Python's beloved range().