Python Ternary Operator
Python’s ternary operator, more formally called a conditional expression, lets you choose between two values based on a condition, all in a single line. Instead of writing a multi-line if/else block just to assign one of two values to a variable, you can express that choice as one compact expression. It doesn’t replace full if statements — it complements them for the specific case of picking a value.
Overview / How it works
In many languages (C, Java, JavaScript) the ternary operator uses the symbols ? and :, like condition ? valueIfTrue : valueIfFalse. Python deliberately does not use punctuation for this — it uses actual keywords, following its philosophy that code should read close to English. The result is what Python calls a conditional expression: value_if_true if condition else value_if_false.
The key thing to understand is that this is an expression, not a statement. In Python, a statement (like a full if/elif/else block) performs an action and does not itself produce a value you can assign or pass around. An expression, by contrast, always evaluates to a single value. Because the conditional expression is an expression, you can use it anywhere a value is expected: on the right-hand side of an assignment, as a function argument, inside a list comprehension, as a default in an f-string, or as a return value.
Internally, when Python’s interpreter encounters A if C else B, it evaluates the condition C first (converting it to a boolean via bool() if it isn’t one already). If C is truthy, the entire expression evaluates to A, and crucially, B is never evaluated at all — this is called short-circuit evaluation. If C is falsy, only B is evaluated and becomes the result; A is skipped. This matters if A or B have side effects (like calling a function that prints something or raises an exception) — only one branch actually runs.
Syntax
The general form is:
value_if_true if condition else value_if_false
Read left to right, this says: “evaluate value_if_true if condition is true, otherwise evaluate value_if_false“. Note the order is different from a plain if statement — the value comes first, then the condition, then the fallback value.
| Part | Meaning |
|---|---|
value_if_true |
Expression evaluated and returned when condition is truthy |
if condition |
Any expression convertible to a boolean; evaluated first |
else value_if_false |
Expression evaluated and returned when condition is falsy; this clause is mandatory in Python |
Unlike some languages, Python’s conditional expression has no shorthand for omitting the else branch — you must always supply both possible values.
Examples
Example 1: A basic value choice
age = 20
status = "adult" if age >= 18 else "minor"
print(status)
Output:
adult
Here age >= 18 evaluates to True, so the whole expression evaluates to "adult" and that string is assigned to status. The string "minor" is never even constructed.
Example 2: Chained conditional expressions in a function
def describe_temperature(celsius: float) -> str:
description = "hot" if celsius >= 30 else "warm" if celsius >= 20 else "cold"
return description
for temp in [35, 25, 10]:
print(f"{temp}\u00b0C is {describe_temperature(temp)}")
Output:
35°C is hot
25°C is warm
10°C is cold
Conditional expressions can be chained because the part after else is itself just another expression — it can be another conditional expression. Python evaluates this right-to-left in terms of nesting: it first checks celsius >= 30; if that’s false, the entire remainder "warm" if celsius >= 20 else "cold" becomes the else value, which is then evaluated on its own. This is legal and sometimes convenient, but as you’ll see in Common Mistakes, chaining too many of these hurts readability.
Example 3: Inside a list comprehension and as a default fallback
scores = [55, 82, 91, 40, 67]
results = ["pass" if score >= 60 else "fail" for score in scores]
print(results)
name = None
display_name = name if name else "Guest"
print(display_name)
Output:
['fail', 'pass', 'pass', 'fail', 'pass']
Guest
The first line shows the most common real-world use: transforming a list, where each element depends on a condition. The second part shows the conditional expression used as a quick way to substitute a default when a value is falsy (None, 0, "", and empty containers are all falsy in Python). Note that this pattern also has a shorthand using or: display_name = name or "Guest" works the same way for this particular case, though it’s less explicit about intent than the ternary form.
Under the hood
When the Python compiler parses A if C else B, it produces bytecode that is functionally similar to a small branch: evaluate C, jump over the code for A if C is false, otherwise jump over the code for B. You can verify this yourself with the dis module, which disassembles compiled bytecode — it shows a POP_JUMP_IF_FALSE instruction (or similar, depending on Python version) that skips straight to the else branch’s bytecode when the condition is false. This confirms that only one branch’s code ever actually executes at runtime; the other branch’s expression is not evaluated, not even to check for errors. That’s why x if x != 0 else 1 / x would be a strange (and safe) way to guard a division, since 1 / x only runs when x is falsy, i.e. equal to 0 — wait, that particular example would actually divide by zero in the false branch, so always design the condition to protect the branch that could fail.
Common Mistakes
Mistake 1: Trying to use C-style ?/: syntax
Programmers coming from C, Java, or JavaScript often try to write:
x = 5
result = x > 0 ? "positive" : "non-positive"
print(result)
This raises a SyntaxError because Python has no ?: operator at all — conditional expressions must use the keywords if and else. The fix is straightforward:
x = 5
result = "positive" if x > 0 else "non-positive"
print(result)
Output:
positive
Mistake 2: Overusing nested ternaries until they’re unreadable
Because conditional expressions can be chained, it’s tempting to build a whole decision ladder out of them:
grade = 73
letter = "A" if grade >= 90 else "B" if grade >= 80 else "C" if grade >= 70 else "D" if grade >= 60 else "F"
print(letter)
Output:
C
This runs correctly, but it’s hard to scan and easy to misread — especially once the line wraps. When you have more than one or two conditions chained, prefer a regular if/elif/else block (often inside a small function), which reads top to bottom in the natural order of the logic:
def letter_grade(grade: int) -> str:
if grade >= 90:
return "A"
elif grade >= 80:
return "B"
elif grade >= 70:
return "C"
elif grade >= 60:
return "D"
else:
return "F"
print(letter_grade(73))
Output:
C
Both versions produce the same result, but the second is far easier to maintain when someone needs to add a new grade band later.
Best Practices
- Reserve the ternary operator for simple, single-condition value choices — if you need more than one level of nesting, switch to a full
if/elif/elsestatement or a small function. - Wrap a conditional expression in parentheses when it’s an argument to a function or part of a larger expression, e.g.
print(("yes" if ok else "no")), to make operator precedence unambiguous to readers even when it isn’t strictly required by the parser. - Don’t use a conditional expression purely for its side effects (like choosing between two
print()calls) — that’s what a plainif/elsestatement is for. Ternaries are for producing a value. - Keep both branches the same type when possible (e.g. both
str, bothint) so the resulting variable has a predictable, consistent type for the rest of your code. - Prefer
x if x else defaultoverx or defaultwhenxcould legitimately be a falsy-but-meaningful value (like0or"") that you don’t actually want replaced — think carefully about which one you actually mean, sinceorreplaces *any* falsy value. - Use ternaries inside comprehensions to keep the transformation logic on one line, but if the condition itself gets long, consider a helper function called from the comprehension instead.
Practice Exercises
- Write a one-line conditional expression that assigns the string
"even"or"odd"to a variableparitybased on whether an integernis divisible by 2. - Given a list of numbers
[3, -1, 0, 8, -5, 2], use a list comprehension with a ternary operator to build a new list where every negative number is replaced with0and all other numbers stay the same. Expected output:[3, 0, 0, 8, 0, 2]. - Write a function
fizz_or_number(n)that returns the string"Fizz"ifnis divisible by 3, and otherwise returnsstr(n), using a single conditional expression in thereturnstatement.
Summary
- Python’s ternary operator is written as
value_if_true if condition else value_if_false, not with?/:. - It is an expression that produces a value, not a statement — use it for assignments, arguments, comprehensions, and return values.
- Only the chosen branch is evaluated; the other branch’s code never runs (short-circuit behavior).
- The
elseclause is always required in Python, unlike some other languages. - Conditional expressions can be chained to emulate
elif, but heavy nesting should be replaced with a realif/elif/elseblock for readability. - Use ternaries for simple, single-condition value choices; reach for full
ifstatements once the logic grows beyond one condition.
