Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

To check whether a number lies between two values in Python, write a chained comparison such as low < number < high. This form excludes both endpoints. To include an endpoint, change its operator to <=. For example, 0 <= score <= 100 accepts both 0 and 100. The rest of this guide covers how to choose each boundary, the cases where the simple check gives a surprising result, and the pandas method for checking many values at once.

Choose the operator for each endpoint

Each endpoint gets its own operator. The choice is independent for the lower and upper bound, which gives four interval shapes:

Interval Python expression Lower bound Upper bound
Open (exclusive both ends) low < number < high Excluded Excluded
Closed (inclusive both ends) low <= number <= high Included Included
Half-open, lower included low <= number < high Included Excluded
Half-open, upper included low < number <= high Excluded Included

The half-open forms are common when ranges must not overlap. For instance, if one tax band runs from 0 up to but not including 10,000 and the next starts at 10,000, the first band uses 0 <= income < 10000, so no income value is counted twice.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Why a chained comparison is the standard form

Python lets you chain comparison operators. The Python language reference defines x < y <= z as equivalent to x < y and y <= z, with one difference: y is evaluated only once. You can therefore write the interval as it reads in mathematics, and you do not repeat the middle expression. If the middle value is a function call, such as low < get_value() < high, the call runs once.

You can also write the longer form, low < number and number < high. It gives the same result for simple values and is useful only when the two conditions belong to different parts of your logic. For a single interval, the chained form is clearer.

A working example

score = 72

if 0 <= score <= 100:
    print("within the allowed range")
else:
    print("out of range")

This prints “within the allowed range”. Replace <= with < on either side to exclude that endpoint. A floating-point value works the same way:

temperature = 36.6

if 36.0 < temperature <= 37.5:
    print("in the target band")

Edge cases that change the result

Reversed bounds return False

The chained check assumes the lower bound is actually lower. If you pass low greater than high, no ordinary number can satisfy both comparisons, so the expression is always False:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
low, high = 100, 0
print(0 <= 50 <= 100)   # True
print(high <= 50 <= low) # False, but no number satisfies this chain

If your inputs may arrive in either order and you want the range between them, normalize the pair first:

low, high = sorted((low, high))
print(low <= number <= high)

Only do this when “between” should mean “between the smaller and larger value”. If a reversed pair signals an input error, validate it and raise an exception instead.

NaN never falls inside an interval

The Python documentation specifies that an ordered comparison involving NaN (not a number) is false. A chained check that includes a NaN therefore returns False, whatever the bounds:

import math

x = float("nan")
print(0 <= x <= 100)        # False
print(math.isnan(x))        # True

If missing or invalid readings should be handled separately, test for NaN before the interval check.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Floating-point boundaries are exact

Comparisons test the stored binary value of a float. A value that prints as 0.3 may not be exactly equal to the literal 0.3 after arithmetic. If your rule depends on an approximate boundary, define the tolerance in code, for example by comparing against high + 1e-9, and document it. Do not widen the interval silently.

Operand types must be orderable

The chain works only when the values can be ordered against each other. Comparing an integer with a float is fine. Comparing a number with an unrelated type, such as a string, raises a TypeError in Python 3. Convert user input with float() or int() and handle the ValueError that a bad conversion raises before running the check.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Why range() is not a general interval check

The expression number in range(low, high) looks similar, but range() represents a sequence of integers with the stop value excluded. It is useful for loops and for testing integer membership with a half-open interval. It does not express a general numeric interval. A float such as 2.5 is never a member of range(0, 10), and the upper bound is always excluded, so it cannot model a closed interval. For ordinary numeric ranges, including floats or a included upper endpoint, use comparison operators.

Checking many values with pandas

For a pandas Series, a Python loop is slow and unnecessary. The Series.between(left, right, inclusive=...) method returns a Boolean Series with one result per row. Recent pandas versions accept the string values "both", "neither", "left", and "right" for inclusive. Older code that passes True or False uses a deprecated form, so check the version you have installed with pandas.__version__.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import pandas as pd

scores = pd.Series([55, 72, 91, 100])
mask = scores.between(60, 100, inclusive="both")
print(mask.tolist())   # [False, True, True, True]
print(scores[mask])

Missing values (NaN) in the Series produce False in the result, consistent with the scalar behavior above. Use the Boolean mask to filter rows or to count matches with mask.sum().

Choosing the right approach

  • Single number, exclusive or inclusive bounds: use low < number < high or low <= number <= high.
  • Half-open bands that must not overlap: choose <= on one side and < on the other.
  • Bounds that may arrive reversed: normalize with sorted() or reject the input.
  • Integer sequences or loop indexes: range() is appropriate.
  • Column of values in a DataFrame or Series: use between() and keep the Boolean mask.

“

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.