Python Total_排序与类继承
据我所知,来自Python Total_排序与类继承,python,python-3.x,inheritance,functools,Python,Python 3.x,Inheritance,Functools,据我所知,来自functools的total\u ordering装饰器不应该很好地处理从有序类继承的类:它不会尝试定义比较函数,因为它们已经定义 请参见此示例: from functools import total_ordering from collections import namedtuple Test = namedtuple('Test',['a','b']) @total_ordering class TestOrd(Test): def __lt__(self,o
functools
的total\u ordering
装饰器不应该很好地处理从有序类继承的类:它不会尝试定义比较函数,因为它们已经定义
请参见此示例:
from functools import total_ordering
from collections import namedtuple
Test = namedtuple('Test',['a','b'])
@total_ordering
class TestOrd(Test):
def __lt__(self,other):
return self.b < other.b or self.b == other.b and self.a < other.a
x = TestOrd(a=1,b=2)
y = TestOrd(a=2,b=1)
print(x < y) # Expected: False
print(x <= y) # False
print(x > y) # True
print(x >= y) # True
print(y < x) # True
print(y <= x) # True
print(y > x) # False
print(y >= x) # False
这让我相信这不是解决问题的正确方法
因此有一个问题:是否有一种正确的方法来重新排序具有总排序的类?
(是的,我知道手工完成
total_排序
的工作很简单,而且我知道在这个例子中,定义一个无序的名为tuple
也很简单。)对于您的例子,您可以通过引入一个不直接从Test继承的附加基类来解决这个问题:
Test = namedtuple('Test',['a','b'])
@total_ordering
class TestOrdBase:
def __lt__(self ,other):
return self.b < other.b or self.b == other.b and self.a < other.a
class TestOrd(TestOrdBase, Test):
pass
Test=namedtuple('Test',['a','b']))
@总订单
类TestOrdBase:
定义(自身、其他):
返回self.b
TestOrd
基类的顺序很重要,TestOrdBase
必须在Test
之前。通过查看,我们可以看到问题:
roots = [op for op in _convert if getattr(cls, op, None) is not getattr(object, op, None)]
这将仔细检查cls
上定义的版本是否不是从object
继承的版本,但将包括任何其他继承的方法(即不替换)。最小的调整是定义您自己的副本(我称之为total\u reordering
),它使用:
roots = set(cls.__dict__) & set(_convert)
(根据"基本法")。这只查看直接在类上定义的方法,从而导致装饰器重写继承的版本。这将提供您希望从以下方面开始的结果:
False
False
True
True
True
True
False
False
请注意,您误解了以下定义:
__gt__ = lambda *_ : NotImplemented
是的;它并没有改变装饰程序所做的事情(在本例中,这算不了什么),它只是覆盖继承的版本,并导致
在运行时被委托给其他方法。“是否有一种正确的方法可以用total\u顺序重新排序类?”-不,正如您所指出的,它只会替换尚未定义的方法,所以继承类必须显式重写所有这些类才能重新排序。@jonrsharpe是否可以将某些方法标记为未定义?毕竟,它可以为>
做,例如……我想你不明白它的作用;它不影响总排序(它寻找的是存在,而不是实现)。如果你移除装饰器,行为不会改变。我想你可以创建一个新的排序修饰符,它只查看直接在特定类上定义的方法(检入\uuu dict\uuuu
而不是dir
)。哦,我明白了,如果\uu gt\uu
没有实现,不管总排序如何,解释器都会依赖\uu lt\uuuu
。谢谢,我确实误解了你的行为。对于你评论的第二部分,这可能是一个想法。或者甚至可以简单地定义一个较弱的装饰器,这将要求我们告诉它它可以信任哪些操作符。啊哈,谢谢!If甚至可以通过更通用的OrdBase
来完成,将比较委托给以后由TestOrd
定义的函数(我猜首选项将取决于我们需要定义多少这样的类,以及子类中需要定义多少)。鸭子打字打得最好!通常将这样的类称为“mixin”,尽管在本例中,它与要将其混合到的类的实现紧密相关。
__gt__ = lambda *_ : NotImplemented