苦练Python第54天:比较运算魔术方法全解析,让你的对象“懂大小、能排序”!

前言

大家好,我是 倔强青铜三 。欢迎关注我,微信公众号:倔强青铜三。欢迎点赞、收藏、关注,一键三连!

欢迎来到 苦练Python第54天!

今天咱们要深入探索Python类中的 比较运算魔术方法,这可是让你的对象**"懂大小、能排序"**的关键所在!

这些魔术方法包括:__lt__、__le__、__eq__、__ne__、__gt__、__ge__ 和 __hash__。

一口气吃透它们,你的类就能在比较、排序、集合操作中如鱼得水!


比较运算魔术方法全家福

方法 触发场景 作用
__lt__ a < b 小于
__le__ a <= b 小于等于
__eq__ a == b 等于
__ne__ a != b 不等于
__gt__ a > b 大于
__ge__ a >= b 大于等于
__hash__ hash(a) 计算对象的哈希值

__lt__:小于操作

作用

定义对象的"小于"逻辑,用于比较两个对象的大小。

触发场景

当你写下 a < b 时,Python会调用 a.__lt__(b)。

示例

python 复制代码
class Student:
    def __init__(self, name, score):
        self.name = name
        self.score = score

    def __lt__(self, other):
        """触发场景:s1 < s2"""
        print("__lt__ 被调用!")
        return self.score < other.score

s1 = Student("张三", 85)
s2 = Student("李四", 90)
print(s1 < s2)  # __lt__ 被调用! -> True

__le__:小于等于操作

作用

定义对象的"小于等于"逻辑。

触发场景

当你写下 a <= b 时,Python会调用 a.__le__(b)。

示例

python 复制代码
class Student:
    ...
    def __le__(self, other):
        """触发场景:s1 <= s2"""
        print("__le__ 被调用!")
        return self.score <= other.score

print(s1 <= s2)  # __le__ 被调用! -> True

__eq__:等于操作

作用

定义对象的"等于"逻辑,默认比较内存地址,但可以通过这个方法自定义。

触发场景

当你写下 a == b 时,Python会调用 a.__eq__(b)。

示例

python 复制代码
class Student:
    ...
    def __eq__(self, other):
        """触发场景:s1 == s2"""
        print("__eq__ 被调用!")
        return self.score == other.score

print(s1 == s2)  # __eq__ 被调用! -> False

__ne__:不等于操作

作用

定义对象的"不等于"逻辑。

触发场景

当你写下 a != b 时,Python会调用 a.__ne__(b)。

示例

python 复制代码
class Student:
    ...
    def __ne__(self, other):
        """触发场景:s1 != s2"""
        print("__ne__ 被调用!")
        return not self.__eq__(other)

print(s1 != s2)  # __ne__ 被调用! -> True

__gt__:大于操作

作用

定义对象的"大于"逻辑。

触发场景

当你写下 a > b 时,Python会调用 a.__gt__(b)。

示例

python 复制代码
class Student:
    ...
    def __gt__(self, other):
        """触发场景:s1 > s2"""
        print("__gt__ 被调用!")
        return self.score > other.score

print(s1 > s2)  # __gt__ 被调用! -> False

__ge__:大于等于操作

作用

定义对象的"大于等于"逻辑。

触发场景

当你写下 a >= b 时,Python会调用 a.__ge__(b)。

示例

python 复制代码
class Student:
    ...
    def __ge__(self, other):
        """触发场景:s1 >= s2"""
        print("__ge__ 被调用!")
        return self.score >= other.score

print(s1 >= s2)  # __ge__ 被调用! -> False

__hash__:哈希值计算

作用

定义对象的哈希值,用于集合操作(如 set 和 dict)。

触发场景

当你调用 hash(a) 或将对象放入集合时,Python会调用 a.__hash__()。

示例

python 复制代码
class Student:
    ...
    def __hash__(self):
        """触发场景:hash(s1) 或 s1 放入集合"""
        print("__hash__ 被调用!")
        return hash(self.score)

print(hash(s1))  # __hash__ 被调用!
students = {s1, s2}  # __hash__ 被调用!

"一键补齐比较运算符" 的装饰器

在 Python 中写一个可排序的类,需要实现 __eq__、__lt__、__le__、__gt__、__ge__ 和 __ne__,样板代码量大且易错。

functools.total_ordering 就是官方给出的"懒癌"解决方案,它是一个 "一键补齐比较运算符" 的装饰器。

装饰器 @total_ordering 会自动生成缺失的比较方法。

前提:你已提供 __eq__ 以及 __lt__、__le__、__gt__、__ge__ 中的任意 一个 。生成的代码逻辑严谨,避免手写 NotImplemented 处理。

使用方法

  1. 导入:from functools import total_ordering
  2. 装饰类:@total_ordering
  3. 实现 __eq__ 和一个顺序方法即可。

示例:学生成绩排序

python 复制代码
from functools import total_ordering

@total_ordering
class Student:
    def __init__(self, name, score):
        self.name, self.score = name, score

    def __eq__(self, other):
        return self.score == other.score

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

# 使用
alice, bob = Student('Alice', 90), Student('Bob', 85)
print(alice > bob)   # True
print(bob <= alice)  # True
print(sorted([bob, alice]))  # [Bob, Alice]

踩坑提示

  • 必须实现 __eq__,否则抛 ValueError。
  • 不要混用 __cmp__(Python 3 已移除)。
  • 同时给出多个顺序方法时,装饰器以最左边为准。

实战:打造可比较、可排序的"分数"类

python 复制代码
from functools import total_ordering

@total_ordering
class Score:
    def __init__(self, value):
        self.value = value

    def __eq__(self, other):
        return self.value == other.value

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

    def __hash__(self):
        return hash(self.value)

    def __repr__(self):
        return f"Score({self.value})"

# 测试
s1 = Score(85)
s2 = Score(90)
s3 = Score(85)

print(s1 < s2)   # True
print(s1 == s3)  # True
print(s1 != s2)  # True
print(s1 > s2)   # False
print(s1 >= s3)  # True

scores = {s1, s2, s3}
print(scores)  # {Score(85), Score(90)}

sorted_scores = sorted([s1, s2, s3])
print(sorted_scores)  # [Score(85), Score(90)]

小结

  • 比较运算魔术方法 让对象支持 < <= == != > >= 比较。
  • __hash__ 是集合操作的关键,必须与 __eq__ 保持一致。
  • 使用 functools.total_ordering 可以简化比较方法的实现。

动手挑战

    1. 实现一个 Person 类,支持按年龄比较大小,并且可以放入集合。
    1. 创建一个 Book 类,支持按书名排序,并且可以通过 hash() 获取哈希值。
    1. 进阶:让 Book 类支持按书名和作者同时比较大小。

互动时间

你最常用哪个比较魔术方法?

A. __eq__(比较狂魔)

B. __lt__(排序狂魔)

C. __hash__(集合狂魔)

评论区告诉我你的答案 + 骚操作!

最后感谢阅读!欢迎关注我,微信公众号 :倔强青铜三。

一键三连(点赞、收藏、关注)!

相关推荐
一条大祥脚5 分钟前
CuTe 与 CuTe DSL:从 C++ 模板元编程到 Python DSL 的 GPU 编程演进
开发语言·c++·python·cutlass·cute·cute dsl
早起CaiCai14 分钟前
【2023-01 OM】利用深度学习算法融合异质观测实现海洋场降尺度
人工智能·深度学习·算法
周杰伦的稻香21 分钟前
AI 助手 2.0:多轮对话、卡片化与文章页感知
人工智能
Martina_032137 分钟前
AI生成3D场景从白模换成精模后镜头全偏了?用6步检查单位、枢轴与层级替换
图像处理·人工智能·3d·ai·自然语言处理·材质·1024程序员节
10年前端老司机41 分钟前
Milvus 8种检索能力实践
数据库·python·agent
狒狒AI1 小时前
手绘白板动画的生产线拆解:AI 出图、笔迹对齐、镜头渲染七道工序(附 21 个开源脚本)
人工智能·aigc
用户2763965765101 小时前
上手 GitHub 官方 Spec Kit:AI 编码别再裸奔,先写 spec 再出码,SDD规约开发
人工智能
Lucas_coding1 小时前
【Agent】Agent 知识地图:核心概念、工程方法与产品生态
人工智能
方方洛1 小时前
ray教程-28-附录G-CICD与Slurm与云上调度
人工智能·分布式·机器学习
疯华整猫1 小时前
混淆起初根本不是为了防破解:我用 Trae 把 Android 混淆这二十来年重跑了一遍
android·人工智能·计算机视觉