Python if-elif-else – The Falsy Integer $50k Bug
if amount: evaluates to False when amount is 0, causing a $50k billing bug.
- Conditional branching in Python: if, elif, else — indentation defines blocks, no braces.
- elif is Python's "else if" — writing else if creates a nested block, not a chain.
- Truthy/falsy: empty containers, None, 0, 0.0, and False are falsy; everything else is truthy.
- Ternary expression: value_if_true if condition else value_if_false (note: condition in the middle).
- Performance: Python short-circuits boolean operators — order conditions wisely to skip expensive checks.
- Production trap: falsy 0 or empty string can trigger else when you meant to handle them as valid values.
Conditional statements let your code make decisions. Think of it like a choose-your-own-adventure book: if this is true, go here; else if that is true, go there; else do this default. Python uses indentations instead of brackets to show which blocks belong together.
Conditional logic is the first place where programs become interesting — where they make decisions. Python's if-elif-else syntax is clean and readable, but there are a few specifics that trip up people coming from other languages.
The main things to get right: truthy and falsy values (Python is more permissive than most languages about what counts as True), the elif keyword (not else if), and the ternary expression syntax which is the reverse of most languages.
Here's the thing most tutorials skip: the subtle production bugs that come from treating falsy values as errors. You'll write if user_input: and it'll silently skip valid input like 0 or an empty string. In real systems, that kind of shortcut costs you hours of debugging.
Basic if-elif-else
The simplest branching constructs. Python executes top-down: the first condition that evaluates to True triggers its block, then the rest of the chain is skipped. Indentation must be consistent — 4 spaces per PEP 8.
if response.timeout: before if response.ok: — the timeout condition never fired because response.ok was True even for timeouts in some libraries.Truthy and Falsy Values
Python evaluates any object in a boolean context. Knowing what is falsy saves you from writing verbose comparisons. But beware: the convenience of if x: can hide logical errors when falsy values are valid inputs.
if x: to check if a number or string is "present" will reject legitimate zeros and empty strings. Always consider the domain: if zero is a valid value, use if x is not None or if x != 0.if user_input: without confirming that empty/falsy is truly invalid for that field.UNSET = object()) instead of relying on truthiness.set(), (), None.Ternary Expression
Python's ternary is the reverse of most languages — condition comes in the middle, not at the start. It's a one-liner, but readability plummets if you chain them. Reserve it for single, obvious conditions.
match-case — Python 3.10+
Python 3.10 added structural pattern matching. It is more powerful than a chain of elif — it can match on structure, not just equality. Use it when you'd otherwise write a long elif chain on a single value or when you need to destructure nested data.
- Matches on type, value, and structure simultaneously.
- Supports guards:
case x if x > 0:adds extra conditions. - Wildcard
_is the default — must come last. - Can match against class instances and custom objects.
Nested Conditionals and Short-Circuit Evaluation
Python evaluates boolean expressions lazily: and stops at the first False, or at the first True. This helps you avoid NoneType errors and expensive function calls. But it also means the order of your conditions matters both for logic and performance.
and/or to collapse simple nests. For more complex cases, extract conditions into named variables or helper functions.log['level'] before checking log is not None. The and guard log and log['level'] failed because a valid empty dict {} is falsy.log is not None and log.get('level').The $50k Billing Bug Caused by Falsy Integers
if amount: was safe because "zero means no transaction" — but discount coupons use $0.00 as a valid value.if amount: evaluates to False when amount is 0 (int or float). The discount application code was in the else branch, so it never ran for zero-dollar coupons.if amount is not None: to distinguish between "no amount" and "amount is zero". Added explicit check for None before processing.- Never use truthiness to check presence of numeric or string values that could legitimately be zero or empty.
- Prefer explicit comparisons:
if x is not Noneorif x != 0overif x. - Add unit tests that explicitly test falsy boundary values (0, 0.0, '', [], etc.).
print(repr(condition)) before the if.else if instead of elif. else if creates a nested block — the second if runs regardless of the first condition's outcome.true_val if condition else false_val. Use parentheses to group complex conditions. Break into full if-else if still unclear.case _: at the end. For structural matching, ensure the value is the exact type expected (e.g., tuple vs list).Key takeaways
Common mistakes to avoid
3 patternsUsing `else if` instead of `elif`
else if with elif. Understand that else if creates a new nested if statement inside the else block.Relying on truthiness for values that can be zero or empty
if x is not None instead of if x when zero or empty are valid values. Document the expected behaviour.Ordering conditions from least to most specific
score > 50) catches values before a more specific one (score > 80), so the specific branch never fires.elif with and to combine conditions.Interview Questions on This Topic
What values are considered falsy in Python?
False, None, zero numeric types (0, 0.0, 0j), empty strings (''), and empty collections ([], {}, set(), (), range(0)). Custom classes can implement __bool__ or __len__ to define their truthiness.Frequently Asked Questions
That's Control Flow. Mark it forged?
3 min read · try the examples if you haven't