A function can return a perfectly valid position for a value that is absent. Python’s bisect functions find where a value belongs in an ordered sequence. Treating that position as a successful lookup can quietly select the next record instead.
Start with a sorted list containing a duplicate:
from bisect import bisect_left, bisect_right
values = [10, 20, 20, 30]
print(bisect_left(values, 20)) # 1
print(bisect_right(values, 20)) # 3
print(bisect_left(values, 25)) # 3
The last result points at thirty, which is a valid insertion boundary for twenty-five. It does not say that twenty-five occurs in the list. For membership, use bisect_left, then check that its returned index is inside the list and that the value at that position equals the requested value. The right insertion boundary can sit after an existing duplicate, so that same forward equality test is not a general recipe for bisect_right.
The official bisect reference explains that the search functions use ordering comparisons rather than calling equality to decide whether they found a match. That makes them useful for boundaries: the left edge of duplicates, the right edge of duplicates, or the first value in a requested range.
The contract assumes the relevant input is already sorted. If an earlier code path appends an out-of-order entry, the search can produce a misleading result without repairing the sequence. Keep the ordering invariant explicit. A list built once and searched many times is a different design from a list modified throughout a request.
For a simple table of threshold scores, the right insertion point can choose the appropriate bucket. For an exact record identifier, a dictionary may express the intention more clearly. Pick the representation around the questions the program needs to answer, including whether duplicate keys and neighboring values matter.
The insertion helpers combine searching with list insertion. A quick boundary search does not make moving the remaining list elements free. Avoid describing the complete update as logarithmic merely because bisection locates its position that way. Measure a real workload before replacing a working data structure for speed.
Keep mutation and concurrent access under control as well. The documentation warns against concurrent use on a sequence that changes during a bisect operation. A correct single-threaded demonstration establishes no synchronization property.
A useful test set contains a duplicate, an absent value between entries, and an absent value beyond the end. Those cases force the caller to handle the boundary as a boundary. Once membership is checked separately, the returned position becomes a useful tool rather than a false success signal.

The Campfire
CommentsThanks. Your comment is waiting for the desk. Once it is approved it appears here within about a minute.
Add a comment