已排序的序列可以用来进行快速搜索,而标准库的 bisect 模块给我们提供了二分查找算法。bisect 模块包含两个主要函数,bisect 和 insort,两个函数都利用二分查找算法来在有序序列中查找或插入元素

bisect 函数其实是 bisect_right 函数的别名,后者还有个姊妹函数叫 bisect_left。它们的区别在于,bisect_left 返回的插入位置是原序列中跟被插入元素相等的元素的位置,也就是新元素会被放置于它相等的元素的前面,而 bisect_right 返回的则是跟它相等的元素之后的位置。这个细微的差别可能对于整数序列来讲没什么用,但是 对于那些值相等但是形式不同的数据类型来讲,结果就不一样了。比如说虽然 1 == 1.0 的返回值是 True,1 和 1.0 其实是两个不同的元素。

bisect可以用来建立一个用数字作为索引的查询表格,比如说把分数和成绩对应起来。 根据一个分数,找到它所对应的成绩:

import bisect
def grade(score, breakpoints=[60, 70, 80, 90], grades='FDCBA'):
    i = bisect.bisect(breakpoints, score)
    return grades[i]

print([grade(score) for score in [60, 33, 99, 77, 70, 89, 90, 100]])

grade函数是很简洁优雅的实现,Pythonic! 这里bisect.bisect不能替换成bisect.bisect_left,否则60分为不及格F。

排序很耗时,因此在得到一个有序序列之后,我们最好能够保持它的有序。bisect.insort 就是为了这个而存在的。insort(seq, item) 把变量 item 插入到序列 seq 中,并能保持 seq 的升序顺序。

insort 可以保持有序序列的顺序:

import bisect 
import random
SIZE = 7
random.seed(1729)
my_list = []
for i in range(SIZE): 
    new_item = random.randrange(SIZE*2) 
    bisect.insort(my_list, new_item) 
    print('%2d ->' % new_item, my_list)

insort 跟 bisect 一样,有 lo 和 hi 两个可选参数用来控制查找的范围。它也有个变体叫 insort_left,这个变体在背后用的是 bisect_left。

整理自《流畅的Python》关于bisect模块的内容。