python - functools total_ordering 似乎对继承的类没有任何作用
问题描述
我正在尝试以使用特殊比较的方式对字符串列表进行排序。我正在尝试使用functools.total_ordering
,但我不确定它是否正确填写了未定义的比较。
我定义的两个( > 和 ==)按预期工作,但 < 没有。特别是,我打印了所有三个,我得到了a > b
和a < b
. 这怎么可能?我认为 total_ordering 会简单地定义<
为not > and not ==
. 我的<
测试结果是您通过常规 str 比较得到的结果,这让我相信 total_ordering 没有做任何事情。
也许问题是我继承了已经__lt__
实现的str?如果是这样,是否有解决此问题的方法?
from functools import total_ordering
@total_ordering
class SortableStr(str):
def __gt__(self, other):
return self+other > other+self
#Is this necessary? Or will default to inherited class?
def __eq__(self, other):
return str(self) == str(other)
def main():
a = SortableStr("99")
b = SortableStr("994")
print(a > b)
print(a == b)
print(a < b)
if __name__ == "__main__":
main()
输出:
True
False
True
解决方案
您是对的,内置str
比较运算符正在干扰您的代码。从文档
给定一个定义一个或多个丰富的比较排序方法的类,这个类装饰器提供其余的。
所以它只提供那些尚未定义的。在您的情况下,其中一些是在父类中定义的事实是无法检测到的total_ordering
。
现在,我们可以更深入地挖掘源代码并找到确切的检查
roots = {op for op in _convert if getattr(cls, op, None) is not getattr(object, op, None)}
所以它检查值是否等于根对象中定义的值object
。我们可以做到这一点
@total_ordering
class SortableStr(str):
__lt__ = object.__lt__
__le__ = object.__le__
__ge__ = object.__ge__
def __gt__(self, other):
return self+other > other+self
#Is this necessary? Or will default to inherited class?
def __eq__(self, other):
return str(self) == str(other)
现在total_ordering
将看到__lt__
、__le__
和__ge__
等于“原始”object
值并根据需要覆盖它们。
说了这么多,我认为这是对继承的不良使用。你至少违反了Liskov 替换str
,因为和之间的混合比较SortableStr
,说得轻松一点,会产生违反直觉的结果。
我更一般的建议是支持组合而不是继承,而不是定义一个“是”专门字符串的东西,而是考虑定义一个“包含”字符串并具有专门行为的类型。
@total_ordering
class SortableStr:
def __init__(self, value):
self.value = value
def __gt__(self, other):
return self.value + other.value > other.value + self.value
def __eq__(self, other):
return self.value == other.value
在那里,不需要魔法。NowSortableStr("99")
是一个有效的对象,它不是一个字符串,但表现出您想要的行为。
推荐阅读
- javascript - 检查是否以编程方式启用了 Google Places API
- c# - 任务中的 ShellProgressBar 子进度条
- r - 使用 latex2exp::TeX 用方程注释用 ggplot2 绘制的图
- javascript - 如何在客户端获取另一个网站的 html?
- android - Android 允许使用某些模式进行深度链接
- c# - 不同 DbContext 之间的一对多
- c# - “finally”块可以更改其“try”块的返回值吗?
- dropdown - 动态加载下拉内容
- swift - 实例成员不能用于类型 - Firebase
- c - 用于保护 C 中结构的基础成员的指针的“const”范围