Comparison Chaining

Write a < b < c like real mathematics — and understand exactly how Python evaluates it.

Most languages force you to write a < b and b < c. Python lets you chain comparisons so the code reads like the maths on paper: a < b < c.

How it actually works

Python rewrites a < b < c as (a < b) and (b < c), with one important twist: the middle expression b is evaluated only once. That matters when b is an expensive function call or has a side effect.

x = 5
print(1 < x < 10)     # True
print(10 < x < 20)    # False

# You can mix operators, too:
print(0 <= x < 10)     # True  (in range [0, 10))

The gotcha to know about

Chaining is and-based, so a == b == c tests that all three are equal — great. But a < b > c is legal and rarely what you mean; keep chains monotonic (all in the same direction) for readability.

Example

Example · python
calls = []

def next_value():
    """A stand-in for an expensive or side-effecting call."""
    calls.append(1)
    return 7

# The middle operand is evaluated exactly ONCE
result = 0 <= next_value() < 10
print('result       :', result)          # True
print('times called :', len(calls))      # 1, not 2

# A clean 'is this a valid grade?' check
def grade_letter(score):
    if not 0 <= score <= 100:
        raise ValueError(f'score {score} out of range')
    if   90 <= score <= 100: return 'A'
    elif 80 <= score < 90:   return 'B'
    elif 70 <= score < 80:   return 'C'
    else:                    return 'F'

for s in (95, 83, 72, 40):
    print(s, '->', grade_letter(s))

# Output:
# result       : True
# times called : 1
# 95 -> A
# 83 -> B
# 72 -> C
# 40 -> F

When to use it

  • A bounds checker uses 0 <= index < length to validate an array index in one readable expression.
  • A date validator writes start <= event_date <= end to confirm a date falls within a window.
  • A grading function uses 70 <= score < 80 inside a chained comparison to assign the B grade band.

More examples

Chained range check

Chains two comparisons so age is tested against both bounds in a single, readable expression.

Example · python
age = 25
if 18 <= age < 65:
    print('Working age adult')

# Equivalent (but longer):
if age >= 18 and age < 65:
    print('Working age adult')

Chaining evaluates each pair once

Illustrates that chained comparisons test each adjacent pair, unlike parenthesised forms that compare booleans.

Example · python
a, b, c = 1, 2, 3
result = a < b < c    # True: 1<2 AND 2<3
print(result)

# Contrast: non-chained version
result2 = (a < b) < c   # (True) < 3  -> 1 < 3 -> True (but different!)
print(result2)

Multi-step strict chain

Shows a strict inequality chain and a mixed-type chain with int/float equality.

Example · python
x = 5
print(1 < x < 10)    # True
print(1 < x < 5)     # False (x is not strictly less than 5)
print(x == 5 == 5.0) # True (chaining works across types)

Discussion

  • Be the first to comment on this lesson.