Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/283.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Total_排序与类继承_Python_Python 3.x_Inheritance_Functools - Fatal编程技术网

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