乐于分享
好东西不私藏

比较运算符 | 文档相似度

比较运算符 | 文档相似度

"""任务:重载比较运算符场景:根据相似度分数比较检索结果"""from functools import total_ordering@total_orderingclass SearchResult:    """检索结果"""    def __init__(self, doc_id, score):        self.doc_id = doc_id        self.score = score    def __lt__(self, other):        """小于"""        return self.score < other.score    def __eq__(self, other):        """等于"""        return self.score == other.score    def __repr__(self):        return f"Result({self.doc_id}, score={self.score})"# 测试result1 = SearchResult("doc1"0.9)result2 = SearchResult("doc2"0.7)result3 = SearchResult("doc3"0.9)assert result1 > result2assert result1 >= result3assert result1 == result3assert result2 < result1# 排序results = [result2, result1, result3]sorted_results = sorted(results, reverse=True)assert sorted_results[0].score >= sorted_results[-1].scoreprint(" 比较运算符测试通过")print(f"排序结果: {sorted_results}")

一、场景

本代码场景是搜索引擎/文档检索系统,用户输入关键词,系统返回一堆文档结果,每个结果有相似度分数(score),按分数从高到低排序。此外还可用于推荐系统(商品 / 视频推荐)、论文检索文本相似度匹配、聊天机器人回答排序等。

二、个人理解/最初卡在哪里

1、没有加 @total_ordering,程序报错。

@total_ordering 是 Python functools 模块里的装饰器。只需要手动写 2 个比较方法:

__lt__(小于)__eq__(等于)

它就会自动生成剩下所有比较运算符:>、>=、<=、!=,不用手写 6 个方法。如果不加@total_ordering,代码里用到了 >、>=,没定义,就会报错。 

以下是 result1 < result2 的内部流程示例:

创建对象

result1 = SearchResult("doc1"0.9)

执行时,会跑 __init__:

def __init__(self, doc_id, score):    self.doc_id = doc_id   # 把 "doc1" 放进自己的 doc_id    self.score = score    # 把 0.9 放进自己的 score

所以:

result1 内部:score = 0.9result2 内部:score = 0.7

当写 result1 < result2 时,Python 会自动调用 result1.__lt__(result2) ,对应到方法里:

def __lt__(self, other):    return self.score < other.score

此时:

self = result1other = result2

即:

def __lt__(self, other):    # self = result1 → score=0.9    # other = result2 → score=0.7    return 0.9 < 0.7

返回 False。

2、直接用 key=lambda 排序更简单,为什么要用类加装饰器@total_ordering?

这种做法是给类定义大小规则,让对象可以比较,然后用 sorted 直接排序。

简单场景用 sorted(…, key=lambda…),对象需要频繁比较,可以用上述方法。两者对比:

results = [    {"doc_id""doc1""score"0.9},    {"doc_id""doc2""score"0.7},]# 排序必须写 keysorted(results, key=lambda x: x["score"], reverse=True)

类 + @total_ordering + 排序

from functools import total_ordering@total_orderingclass SearchResult:    def __init__(self, doc_id, score):        self.doc_id = doc_id        self.score = score    def __lt__(self, other):        # 核心:告诉 Python 用 score 比较大小        return self.score < other.score    def __eq__(self, other):        return self.score == other.score    def __repr__(self):        return f"Result({self.doc_id}, score={self.score})"# 1. 创建一堆对象result1 = SearchResult("doc1"0.9)result2 = SearchResult("doc2"0.7)result3 = SearchResult("doc3"0.9)# 放进列表results = [result2, result1, result3]# 2. 直接排序# 不用写 key,不用写 lambdasorted_results = sorted(results, reverse=True)# 打印看结果print("排序前:", results)print("排序后:", sorted_results)

希望对象能直接比大小、要反复比较很多次:

result1 > result2   # 直接比较对象result1 == result3

而不是:

result1["score"] > result2["score"]

就用上述代码方法,不使用 key=lambda。

三、代码中的关键洞察

比较的不是对象本身,而是对象里的分数(score)。

四、关键代码/可复用片段

from functools import total_ordering@total_orderingclass 类名:    def __init__(self, value):        self.value = value    def __lt__(self, other):        return self.value < other.value    def __eq__(self, other):        return self.value == other.value