25
votes

Somehow, this works:

def in_range(min, test, max):
    return min <= test <= max

print in_range(0, 5, 10)  # True
print in_range(0, 15, 10)  # False

However, I can't quite figure out the order of operations here. Let's test the False case:

print 0 <= 15 <= 10  # False
print (0 <= 15) <= 10  # True
print 0 <= (15 <= 10)  # True

Clearly, this isn't resolving to a simple order of operations issue. Is the interval comparison a special operator, or is something else going on?

2
print (0 <= 15) <= 10 evaluates to True. But It makes no sense to ask True <= 10, even if it is defined by Python. I think in these cases it is best to think "Pythonic"; what is the concept that we are trying to do here? A: We do indeed get the interval comparison as desired. - information_interchange

2 Answers

35
votes

Unlike most languages, Python supports chained comparison operators and it evaluates them as they would be evaluated in normal mathematics.

This line:

return min <= test <= max

is evaluated by Python like this:

return (min <= test) and (test <= max)

Most other languages however would evaluate it like this:

return (min <= test) <= max
5
votes

As specified in the Python documentation:

Comparisons can be chained arbitrarily, e.g., x < y <= z is equivalent to x < y and y <= z, except that y is evaluated only once (but in both cases z is not evaluated at all when x < y is found to be false).

Formally, if a, b, c, ..., y, z are expressions and op1, op2, ..., opN are comparison operators, then a op1 b op2 c ... y opN z is equivalent to a op1 b and b op2 c and ... y opN z, except that each expression is evaluated at most once.