🕯️ Magic Note
Chained comparisons are evaluated from left to right, but each expression in the middle is evaluated only once. This is different from writing a < b and b < c where b could be evaluated twice if it is a function call. Python’s chaining is both elegant and efficient.
Python
score = 75
# Check if score is between 60 and 80
if 60 <= score <= 80:
print(“Good score!”)
# Check if score is strictly between 50 and 100
if 50 < score < 100:
print(“Score is in range”)
temperature = 22
if 18 <= temperature <= 25:
print(“Comfortable temperature”)
Python
x = 5
y = 10
z = 15
# Mixing operators
print(x < y <= z) # True (5 < 10 is True, 10 <= 15 is True)
print(x == y < z) # False (x == y is False, so chain fails)
print(x < y != z) # True (5 < 10 is True, 10 != 15 is True)
print(x < y >= z) # False (5 < 10 is True, but 10 >= 15 is False)
🕯️ Magic Note
Python does not limit you to using the same operator throughout the chain. a < b == c > d is perfectly valid. It evaluates to True only if all four comparisons are True. This is powerful but can become hard to read. Use with care.
Python
# A function that prints when called
def get_middle_value():
print(“get_middle_value was called”)
return 5
# Using chaining (function called once)
result = 1 < get_middle_value() < 10
# Output: get_middle_value was called (only once)
print(result) # True
# Without chaining (function called twice if first comparison is True)
temp = get_middle_value()
result = 1 < temp and temp < 10
# But careful: this also evaluates the function once if stored in variable
Python
# Using walrus operator in a chain
if 1 < (x := get_value()) < 10:
print(f”x is {x} and it is between 1 and 10″)
# Without walrus, you would need multiple lines
x = get_value()
if 1 < x < 10:
print(f”x is {x} and it is between 1 and 10″)
Python
word = “magic”
# Check if word comes between “apple” and “zebra” alphabetically
if “apple” < word < “zebra”:
print(f”{word} is in the dictionary range”)
# Chained string comparisons
print(“a” < “b” < “c”) # True
print(“cat” < “dog” < “eagle”) # True
print(“apple” > “banana” > “cherry”) # False (apple > banana is False)
Python
# List comparisons in a chain
print([1, 2] < [1, 2, 3] < [1, 2, 4]) # True
print([1, 3] > [1, 2] > [1, 1]) # True
# Tuple comparisons
print((1, 2) < (1, 3) < (2, 0)) # True
Python
def risky_operation():
print(“Risky operation was called”)
return 100
x = 5
# First comparison (x > 10) is False, so risky_operation() never runs
if x > 10 < risky_operation():
print(“This won’t print”)
# risky_operation() is NOT called (short-circuit)
# However, the middle value in a chain is not short-circuited the same way
# In 1 < x < 10, x is evaluated once regardless
🕯️ Magic Note
Short-circuiting in chained comparisons is subtle. In a < b < c, b is always evaluated. But if a < b is False, then b < c is never evaluated. This matches how and short-circuits.
Python
a = [1, 2]
b = a
c = a
# Chaining is operators
print(a is b is c) # True (all refer to same object)
x = “hello”
y = “hello”
z = “hello”
# May be True due to string interning, but not guaranteed
print(x is y is z) # May be True (implementation dependent)
Python
x = 5
# Normal chaining
print(1 < x < 10) # True
# With parentheses – changes meaning
print(1 < (x < 10)) # 1 < True (True becomes 1) → False
print((1 < x) < 10) # True < 10 (True becomes 1) → True
# Parentheses are useful for complex conditions though
print(1 < x and (x < 5 or x > 8)) # x=5 → False
Python
# 1. Input validation
age = int(input(“Enter age: “))
if 0 <= age <= 120:
print(“Valid age”)
# 2. Grade boundaries
score = 85
if 90 <= score <= 100:
grade = “A”
elif 80 <= score < 90:
grade = “B”
# 3. Time range checks
hour = 14
if 9 <= hour <= 17:
print(“Working hours”)
# 4. Boundary conditions
value = 0
if -1 < value < 1:
print(“Value is near zero”)
- Using parentheses incorrectly: 1 < (x < 10) compares 1 to a boolean
- Thinking all operators in a chain must be the same (they do not)
- Forgetting that a < b > c is valid but can be less readable than a < b and b > c
- Using chained comparisons with incompatible types (TypeError)
- Writing x == y == z when you meant x == y and y == z (this actually works, but be clear about intent)
- Write a chained comparison that checks if x is between 10 and 20 (inclusive).
- What is the difference between 1 < x < 10 and 1 < (x < 10)?
- Does a < b > c mean the same as a < b and b > c?
- What happens if the first comparison in a chain is False?
- Write a chained comparison that checks if a string comes between “apple” and “zebra” alphabetically.
⚡ Whisper
Mathematicians have written 1 < x < 10 for centuries. Programmers in other languages cannot. They must write 1 < x and x < 10. Python chose the path of the mathematician. The path of natural thinking. The path of reading code the way you read a sentence. “If x is greater than 1 and less than 10” becomes “if 1 is less than x is less than 10.” This is not a trick. This is Python respecting how humans already think. Chain your comparisons. Write code that reads like a story. Your future self will understand it instantly. That is the conjure of clarity.