On sorted data you can find a value without scanning it all: look at the middle item, then keep only the half where the value must be. Each step halves the range, so a million items need about 20 steps (O(log n)).
The hand-written version keeps two bounds, lo and hi, and moves one past mid each time: lo = mid + 1 or hi = mid - 1. Setting lo = mid instead can leave the range stuck and loop forever.
The bisect module does it for you:
bisect_left(a, x): the first position where x could go, before any equal values.
bisect_right(a, x): the position after any equal values.
bisect_right(a, hi) - bisect_left(a, lo) counts the values between lo and hi.
This is how tax brackets, price bands and "first day we hit the target" lookups are done.
from bisect import bisect_left, bisect_right
prices = [5, 9, 9, 12, 20]
bisect_left(prices, 9), bisect_right(prices, 9), bisect_right(prices, 12) - bisect_left(prices, 9)
Out: (1, 3, 3). There are three prices from 9 to 12.