说明
《Python 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
Python 内置模块 functools 的一个高阶函数装饰器 @functools.total_ordering
,它用在给定一个声明一个或多个全比较排序方法的类中,这个类装饰器实现剩余的方法,这样减轻了指定所有可能的全比较操作的工作。
给定一个定义了一个或多个富比较排序方法(rich comparison ordering methods)的类,这个类装饰器提供其余的方法,这简化了指定所有可能的富比较操作所涉及的工作。一个例子快速了解:
from functools import total_ordering
@total_ordering
class Num:
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
# 执行代码
Num(2) < Num(3) # True
Num(2) > Num(3) # False
Num(3) == Num(3) # False
Num(3) == Num(5) # True
简单说:
__eq__()
(等于) 方法,但不必显式定义四个富比较列表:
__lt__()
小于__le__()
小于等于__gt__()
大于__ge__()
大于等于类中定义了两个比较方法:一个定义相等,一个定义顺序。其他比较方法由 @total_ordering 基于这两个定义完成,包括 __le__()
、__gt__()
和 __ge__()
等,不等比较方法__ne__()
默认基于__eq__()
生成,装饰器无须参与。
注意:total_ordering 函数都直接调用根魔术(特殊)方法,而不是使用相应的运算符,这避免了当操作符分派逻辑检测到 NotImplemented 结果,然后调用反射方法时可能出现的无限递归。
有时候装饰器生成的运算符并不是完全理想的。
其他说明:
最终实现的六种富类比较方法是:
object.__lt__(self, other)
object.__le__(self, other)
object.__eq__(self, other)
object.__ne__(self, other)
object.__gt__(self, other)
object.__ge__(self, other)
为什么要全富对比方法的补全呢?因为不能仅依据 __le__
或者 __ge__
确定对比顺序,是因为你不能假设你可以交换 a 和 b,比如 a 大于 b 并不意味着 b 小于 a。
如果 b 是不同类型的 b.__le__
可能无法实现,因此无法保证 a < b <=> not (b <= a)
映射。如果未定义 __le__
,但已定义 __lt__
,则实现将使用 (a <= b)
和 (a != b)
。
映射的完整表如下所示:
比较 | 可得出 | 替代 |
---|---|---|
a > b |
a < b |
(not a < b) and (a != b) |
a <= b |
(not a <= b) |
|
a >= b |
(a >= b) and (a != b) |
|
a <= b |
a < b |
(a < b) or (a == b) |
a > b |
(not a > b) |
|
a >= b |
(not a >= b) or (a == b) |
|
a < b |
a <= b |
(a <= b) and (a != b) |
a > b |
(not a > b) and (a != b) |
|
a >= b |
(not a >= b) |
|
a >= b |
a < b |
(not a < b) |
a <= b |
(not a <= b) or (a == b) |
|
a > b |
(a > b) or (a == b) |
__eq__
方法是可选的,因为基类 object 为您默认定义,只有当两个实例是同一对象时,才认为它们相等,仅当 ob1 为 ob2 时,ob1==ob2。
例如,在以下的 Student 类中,支持 __eq__()
(等于) 方法,它仅实现了__lt__()
小于,但用了 @total_ordering
装饰后,就实现了其他的富比较方法:
@total_ordering
class Student:
def _is_valid_operand(self, other):
return (hasattr(other, "lastname") and
hasattr(other, "firstname"))
def __eq__(self, other):
if not self._is_valid_operand(other):
return NotImplemented
return ((self.lastname.lower(), self.firstname.lower()) ==
(other.lastname.lower(), other.firstname.lower()))
def __lt__(self, other):
if not self._is_valid_operand(other):
return NotImplemented
return ((self.lastname.lower(), self.firstname.lower()) <
(other.lastname.lower(), other.firstname.lower()))
以下是版本迭代:
更新时间:2022-01-19 23:28:52 标签:python 装饰器 排序