Problem Solved

Python · ternary operator

Home › Courses › Python › Problems › Ternary operator
🐍 Concept · 2 min read

The ternary operator.
a if condition else b.

Python's one-line conditional. It's not condition ? a : b like in C or JavaScript — it's a if condition else b, which reads as "a if condition is true, otherwise b." It's an expression, not a statement, which means it produces a value. Use it for simple conditional assignments. Use if/else for anything more complex. This page covers the syntax, the precedence traps, and the patterns where ternary actually improves the code.

Short answer: x = a if condition else b — returns a if condition is true, otherwise b. It's an expression — assignable, passable, usable in comprehensions. Not the same as condition ? a : b. Parenthesize when combined with other operators: (a if b else c) + 1. Use it for simple two-choice values. Use if/else for multiple statements or side effects. Nested ternaries are valid but risky — past two levels, use if/elif/else.

✅ The syntax

Python's order is different from C.

ternary.py
age = 20

# C/JS style (NOT Python)
# result = age >= 18 ? 'adult' : 'minor'  # SyntaxError

# Python style
result = 'adult' if age >= 18 else 'minor'
print(result)  # 'adult'

# The structure:
# value_if_true if condition else value_if_false

# Simple value selection
x = 10
y = 20
max_val = x if x > y else y
print(max_val)  # 20

# In a function return
def sign(n):
    return 'positive' if n > 0 else 'negative' if n < 0 else 'zero'

print(sign(5))   # 'positive'
print(sign(-3))  # 'negative'
print(sign(0))   # 'zero'

# In a function argument
print('yes' if age >= 18 else 'no')  # 'yes'

# In a list comprehension
nums = [-2, -1, 0, 1, 2]
clamped = [x if x > 0 else 0 for x in nums]
print(clamped)  # [0, 0, 0, 1, 2]

# In a dict value
config = {'debug': True if age > 0 else False}
print(config)  # {'debug': True}

# Assigned to a variable
status = 'active' if age >= 18 else 'inactive'
print(status)  # 'active'
Syntax comparison:

C, JavaScript, Java, C#:
  condition ? value_if_true : value_if_false
  age >= 18 ? 'adult' : 'minor'

Python:
  value_if_true if condition else value_if_false
  'adult' if age >= 18 else 'minor'

Why the different order:

  The C ternary puts the condition first — you read
  "if condition then X else Y" as "condition ? X : Y".
  
  Python puts the value first — you read "X if
  condition else Y" as "give me X in the case
  where condition holds."

  Both are valid. Python's order matches natural
  language better: "give me 'adult' if the person
  is 18 or over, otherwise 'minor'."

The structure:

  ┌── value_if_true
  │    ┌── condition
  │    │       ┌── value_if_false
  │    │       │
  'adult' if age >= 18 else 'minor'

Read left to right:
  "'adult' if age >= 18, else 'minor'."

The condition can be any expression:

  x if x else y          # truthiness
  x if x > 0 else y      # comparison
  x if name else y       # any truthy value
  x if a and b else y    # boolean operators
  x if not flag else y   # negation
  x if func() else y     # function call

The values can be any expression:

  'a' + 'b' if cond else 'c' + 'd'
  fn1() if cond else fn2()
  [1, 2] if cond else [3, 4]
  {k: v} if cond else {}
  None if cond else value

Ternary is an expression, not a statement.
You can use it anywhere an expression is allowed.

Where it's not allowed:

  ❌ condition ? a : b    # not Python
  ❌ a if cond else b if cond2 else c   # ambiguous
     (actually valid, but reads confusingly)
  ❌ var = a if cond else b = c   # can't assign in ternary

The last one:
  You can't do `x = a if cond else b` where a or b is
  an assignment. Ternary chooses between values,
  not between statements.

✅ Ternary vs if/else

Expression vs statement.

vs-if-else.py
age = 20

# ✅ Ternary — for simple value selection
status = 'adult' if age >= 18 else 'minor'

# ✅ if/else — same result, more lines
if age >= 18:
    status = 'adult'
else:
    status = 'minor'

# Both work. Ternary is shorter.

# ❌ if/else for simple value — verbose
if age >= 18:
    result = 'adult'
else:
    result = 'minor'

# ✅ ternary — cleaner
result = 'adult' if age >= 18 else 'minor'

# ❌ ternary for multiple statements — impossible
# You can't do:
#   do_something() if cond else do_something_else()
#   and call another function after
# Each branch of a ternary is a single expression.

# ✅ if/else — for multiple statements
if age >= 18:
    status = 'adult'
    log('Adult access granted')
    notify('Welcome')
else:
    status = 'minor'
    log('Minor access restricted')

# ❌ ternary for side effects — confusing
# result = log('hi') if cond else log('bye')
# This works technically, but the intent is unclear.
# log returns None, so result is None either way.
# Better to use if/else for side effects.

# ✅ ternary — pure value selection
result = min(a, b) if a < b else b
# This computes a value. Readable.

# ❌ ternary — value selection with side effects
result = (do_x(), x)[0] if cond else (do_y(), y)[0]
# Tuples with side effects. Terrible.
# Use if/else.

# The rule:
#   Ternary — I'm choosing between two VALUES.
#   if/else  — I'm choosing between two CODE PATHS.

# Ternary produces a value:
result = a if cond else b

# if/else runs code:
if cond:
    do_a()
    do_b()
else:
    do_c()
    do_d()
The two roles:

Ternary — expression:
  → produces a value
  → one line
  → both branches must be expressions
  → can be used inside other expressions
  → examples:
    x = a if cond else b
    return 'yes' if ok else 'no'
    [x if x > 0 else 0 for x in nums]
    f(a if cond else b)

if/else — statement:
  → runs code
  → multi-line
  → each branch can have any statements
  → can't be used as an expression
  → examples:
    if cond:
        x = a
        log(x)
    else:
        x = b
        log(x)

The gray area:

  # These are equivalent:
  status = 'adult' if age >= 18 else 'minor'
  
  if age >= 18:
      status = 'adult'
  else:
      status = 'minor'
  
  # Both are correct. Use ternary for brevity.

  # These are NOT equivalent:
  result = a if cond else b
  # vs
  if cond:
      result = a
  else:
      result = b
  # Actually — they ARE equivalent. But the ternary
  # is one line, the if/else is four. For a single
  # assignment, prefer the ternary.

When ternary hurts readability:

  # Nested ternary — hard to parse
  grade = 'A' if s >= 90 else 'B' if s >= 80 else 'C'
  
  # Same logic with if/elif/else — clearer
  if s >= 90:
      grade = 'A'
  elif s >= 80:
      grade = 'B'
  else:
      grade = 'C'
  
  The if/elif/else is longer but each condition
  is on its own line. Easier to add cases, change
  thresholds, debug.

When ternary improves readability:

  # Verbose if/else for a single value
  if user:
      name = user.name
  else:
      name = 'Anonymous'
  
  # Compact ternary
  name = user.name if user else 'Anonymous'
  
  # The ternary makes it clear: 'choose between
  # user.name and 'Anonymous' based on user.'
  # The if/else makes you read four lines for the
  # same information.

The rule:
  If the ternary fits on one line and reads
  left to right like English, use it.
  If it doesn't, use if/else.

For a single conditional assignment, ternary.
For anything more, if/else.

Performance: no difference.
The choice is about clarity, not speed.

✅ The precedence trap

Where ternary binds relative to other operators.

precedence.py
a = 1
b = 2
c = 3
cond = True

# ⚠️ Arithmetic binds tighter than ternary
# result = a if cond else b + c
# Parsed as: a if cond else (b + c)
# = 1 if True else 5 = 1

print(a if cond else b + c)  # 1

# If you meant (a if cond else b) + c:
print((a if cond else b) + c)  # 4

# ⚠️ Comparison binds tighter than ternary
# result = a < b if cond else c
# Parsed as: (a < b) if cond else c
# = True if True else 3 = True

print(a < b if cond else c)  # True

# If you meant a < (b if cond else c):
print(a < (b if cond else c))  # True

# ⚠️ Assignment binds looser — always parenthesize
x = a if cond else b   # OK: x = (a if cond else b)
print(x)  # 1

# ⚠️ Lambda binds looser than ternary
# So: lambda: a if cond else b
# is: lambda: (a if cond else b)
f = lambda: a if cond else b
print(f())  # 1

# But: lambda: a, b if cond else c
# is confusing. Parenthesize.

# ⚠️ Nested ternary — right-associative
result = 'a' if cond else 'b' if cond else 'c'
# Parsed as: 'a' if cond else ('b' if cond else 'c')
# Since cond is True, result is 'a'
print(result)  # 'a'

# If cond were False, it'd evaluate:
# 'b' if False else 'c' → 'c'

# ✅ Safe form — always parenthesize
result = 'a' if cond else ('b' if cond else 'c')
# Same parsing, but explicit.

# ✅ Better — if/elif/else for multiple conditions
if cond:
    result = 'a'
elif cond:
    result = 'b'
else:
    result = 'c'
Operator precedence in Python:

From highest to lowest (relevant subset):

  1. () — parentheses (always win)
  2. ** — exponentiation
  3. * / % // — multiplication
  4. + - — addition
  5. << >> — bit shifts
  6. & — bitwise AND
  7. ^ | — bitwise XOR / OR
  8. in, not in, is, is not, <, <=, >, >=, !=, ==
  9. not — logical NOT
  10. and — logical AND
  11. or — logical OR
  12. if ... else ... — conditional expression
  13. lambda — lambda expression
  14. =, +=, -=, etc. — assignment (lowest)

What this means for ternary:

  Ternary is VERY LOW precedence.
  Only lambda and assignment bind looser.

  So everything else evaluates first:

  a if cond else b + c
  → a if cond else (b + c)
  → because + binds tighter than if/else

  a == b if cond else c
  → (a == b) if cond else c
  → because == binds tighter

  a if cond else b if cond2 else c
  → a if cond else (b if cond2 else c)
  → because nested ternary is right-associative

The safe rules:

✅ Parenthesize the branches if they contain
   other operators:
   
   (a + b) if cond else (c * d)
   
   This is always correct. Clear intent.

✅ Parenthesize nested ternaries:
   
   a if c1 else (b if c2 else d)
   
   Even though it parses correctly without
   parentheses, the parentheses signal
   "this is a nested decision."

✅ Parenthesize when mixing with comparisons:
   
   (a if cond else b) == c
   vs
   a if cond else (b == c)
   
   Two completely different meanings.

✅ Parenthesize when using ternary as an operand:
   
   (a if cond else b) + 1
   vs
   a if cond else (b + 1)
   
   +1 applies to the result, or to b, depending
   on parentheses.

The rule: if you have to think about precedence,
parenthesize. The parentheses cost nothing, and
they document intent.

The nested ternary — a special case:

  x = 'a' if c1 else 'b' if c2 else 'c' if c3 else 'd'
  
  This parses as:
    'a' if c1 else (
      'b' if c2 else (
        'c' if c3 else 'd'
      )
    )
  
  Right-associative: each if/else covers
  everything to its right.
  
  You'd use this for a chain of conditions:
    score 90+ → 'A'
    score 80+ → 'B'
    score 70+ → 'C'
    else      → 'F'
  
  grade = 'A' if s >= 90 else 'B' if s >= 80 else 'C' if s >= 70 else 'F'
  
  This is readable ENOUGH at 4 levels.
  At 5+, use if/elif/else.
  
  The Python style guide (PEP 8) says:
  "Compound statements (multiple statements
  on the same line) are generally discouraged."
  But single-line ternaries are fine.
  
  The line for me: if it doesn't fit in 79
  characters (PEP 8's line length), or if you
  have to count if/elses to understand it,
  use if/elif/else.

Don't nest ternaries more than two levels deep. A two-level nested ternary like 'A' if s >= 90 else 'B' if s >= 80 else 'F' is readable — the chain of conditions is clear. A four-level nested ternary is not. Each additional level makes the reader work harder to trace which condition maps to which value. The fix is always the same: use if/elif/else. It's more lines but each condition is on its own line. You can add cases, change thresholds, or debug by adding a print in one branch. The ternary saves keystrokes at the cost of clarity — and clarity is what maintenance is made of.

⚠️ Common mistakes

The ternary mistakes that cost real time.

1. Using condition ? a : b

SyntaxError. Fix: a if condition else b.

2. Missing the else

x = a if cond — SyntaxError. Fix: ternary needs both branches.

3. Wrong order

x = cond if a else b — misinterpreted. Fix: x = a if cond else b.

4. Forgetting parentheses with operators

a if cond else b + 1 parses as a if cond else (b + 1). Fix: parenthesize.

5. Using ternary for side effects

result = do_x() if cond else do_y() — unclear. Fix: use if/else.

6. Deeply nested ternary

4+ levels — unreadable. Fix: use if/elif/else.

7. Ternary in a comprehension without parenthesizing

[x if x > 0 else 0 for x in nums] — works, but [x if x > 0 for x in nums] is a filter. Different semantics.

8. Using ternary for anything other than value selection

Multiple statements, side effects, complex logic — all wrong for ternary. Fix: if/else.

❓ Frequently asked

What is the ternary operator in Python?

The ternary operator is Python's one-line conditional expression: x if condition else y. It evaluates condition; if true, returns x; if false, returns y. It's an expression, not a statement — it produces a value that can be assigned, passed to a function, or used in a comprehension.

What is the difference between ternary and if/else?

Three differences. (1) Ternary is an expression — it produces a value. if/else is a statement — it executes code. (2) Ternary is one line. if/else is multiple. (3) Ternary evaluates one of two expressions; if/else can run any code. Use ternary when choosing between two values. Use if/else when running different code paths.

Can I nest ternary operators?

Yes, but it's usually a bad idea. Nested ternaries like x = 'a' if c1 else 'b' if c2 else 'c' work — Python evaluates right-to-left. But readability drops fast. Beyond two levels, use if/elif/else statements or a dictionary dispatch.

Why does my ternary produce the wrong value?

Two common causes. (1) Operator precedence: a if b else c + 1 is parsed as a if b else (c + 1) — the ternary binds looser than arithmetic. Parenthesize if needed. (2) Evaluation order: a if b else c evaluates b first, then evaluates only one of a or c. If the unused branch has side effects, they don't happen.

Can I use ternary in a list comprehension?

Yes, and it's common. Example: [x if x > 0 else 0 for x in nums] — replaces negatives with zero. The ternary goes before the 'for' clause in a comprehension. If you want to filter based on a condition, use the 'if' clause after 'for': [x for x in nums if x > 0].

Is the ternary operator faster than if/else?

No, effectively the same. In CPython, both compile to similar bytecode. For a simple expression, the difference is measured in nanoseconds. Don't choose based on performance. Choose based on readability.

🔗 Continue learning

🗺️ Python learning path
The full roadmap from install to first project — every concept in order

Next in this series:

📂 How to check if a file exists
pathlib, os.path, and the try/except pattern that avoids race conditions
← All Python problems
Problem solved · Python