前言
大家好,我是 倔强青铜三 。欢迎关注我,微信公众号:倔强青铜三。欢迎点赞、收藏、关注,一键三连!
欢迎来到 苦练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
处理。
使用方法
- 导入:
from functools import total_ordering
- 装饰类:
@total_ordering
- 实现
__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
可以简化比较方法的实现。
动手挑战
-
- 实现一个
Person
类,支持按年龄比较大小,并且可以放入集合。
- 实现一个
-
- 创建一个
Book
类,支持按书名排序,并且可以通过hash()
获取哈希值。
- 创建一个
-
- 进阶:让
Book
类支持按书名和作者同时比较大小。
- 进阶:让
互动时间
你最常用哪个比较魔术方法?
A. __eq__
(比较狂魔)
B. __lt__
(排序狂魔)
C. __hash__
(集合狂魔)
评论区告诉我你的答案 + 骚操作!
最后感谢阅读!欢迎关注我,微信公众号 :
倔强青铜三
。一键三连(点赞、收藏、关注)!