我经常使用namedtuple个课程。我一直在想今天是否有一种很好的方法来为这样的类实现自定义排序,即使默认排序键不是namedtuple的第一个元素(然后是第二个,第三个等)。
我的第一直觉是实施__lt__
和__eq__
,让total_ordering
完成剩下的工作(它填写了le,ne,gt,ge):
from collections import namedtuple
from functools import total_ordering
@total_ordering
class B(namedtuple('B', 'x y')):
def __lt__(self, other):
return self.y < other.y
然而:
def test_sortingB():
b1 = B(1, 2)
b2 = B(2, 1)
assert b2 < b1 # passes
assert b2 <= b1 # fails
哦,对...... total_ordering
只填写其他方法if they are missing。由于tuple / namedtuple有这样的方法,total_ordering对我没有任何作用。
所以我想我的选择是
有关解决此问题的最佳方法的建议?
答案 0 :(得分:11)
选项1.使用mixin并将total_ordering应用于
@total_ordering
class B_ordering(object):
__slots__ = () # see Raymond's comment
def __lt__(self, other):
return self.y < other.y
class B(B_ordering, namedtuple('B', 'x y')):
pass
选项2.根据total_ordering
创建自己的装饰器,然后使用
答案 1 :(得分:3)
如果,正如您的问题所暗示的那样,您的兴趣仅在于通过备用键在排序命名元组中,为什么不在key
函数中使用sort / sorted attrgetter
参数:
>>> from collections import namedtuple
>>> from operator import attrgetter
>>> P = namedtuple("P", "x y")
>>> p1 = P(1, 2)
>>> p2 = P(2, 1)
>>> sorted([p1, p2], key=attrgetter("y"))
[P(x=2, y=1), P(x=1, y=2)]
您可以更进一步,定义自己的排序功能:
>>> from functools import partial
>>> sortony = partial(sorted, key=attrgetter("y"))
>>> sortony([p1, p2])
[P(x=2, y=1), P(x=1, y=2)]
答案 2 :(得分:1)
我的建议是使用您希望对它们进行排序的顺序创建您的namedtuple。您可能必须更改代码中创建值的部分(例如,将someTuple("name", 24)
更改为someTuple(24, "name")
,但通常会在比使用的地方更少的位置创建值,因此这不应该'这是一个太大的交易。这避免了编写所有比较方法的麻烦,并且作为奖励也避免了一直调用这些自定义比较方法的额外性能开销。