2012-09-27 26 views
7

我使用namedtuple类很多。我一直在想,如果有一种很好的方法来为这样的类实现自定义排序,即使默认排序键不是第一个元素(然后是第二个,第三个等)的namedtuple。在namedtuple类上自定义排序

我的第一反应是实现__lt____eq__total_ordering做休息(它填补了乐,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对我来说没有任何帮助。

所以我想我的选择是

  1. 停止使用namedtuple,只是建立自己的无聊的课,继续使用total_ordering使用namedtuple
  2. 保管和使用namedtuple和插入实现所有6种比较方法
  3. 保持作为第一个字段的排序值。幸运的是,我没有太多类的实例,但通常我只是依靠字段的顺序来初始化它们,这可能是讨厌的。也许这是一个坏习惯。

有关解决此问题的最佳方法的建议?

+0

为什么不只是按照您想排序的顺序创建namedtuple字段? – BrenBarn

+0

我没有意识到我想排序/最大等,直到我已经创建并使用它一段时间。所以我现在可以添加一个领先的领域作为排序领域,但它可能有点破坏性。 – pfctdayelise

+1

但是你如何使用namedtuple?关于namedtuple的好处是它可以让你按名称访问项目,所以你可以改变你的namedtuple,让字段按照正确的顺序,而不会影响你的代码,只要你按名称访问字段(这可能是你在做什么,或者为什么使用namedtuple?)。 – BrenBarn

回答

10

OPTION 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

+1,mixin解决方案很好。 – nneonneo

+0

选项1和选项2的开销是否有显着差异? – Will

+0

+1。选项1是total_ordering问题的直接解决方案,只填写缺失值。 @ Will选项1的开销几乎为零(在方法解析顺序中增加了一个额外的步骤@JohnLaRooy,我建议在你的Option1中加入\ _ \ _ slots \ _ \ _ =()以恢复内存效率 –

1

我的建议是创建您的namedtuple与其他你希望他们排序的字段。您可能需要更改代码中创建值的部分(例如,将someTuple("name", 24)更改为someTuple(24, "name"),但通常创建的值比使用的位置更少,因此这应该不会太大。避免了编写所有的比较方法的麻烦,并作为奖金也避免了这些自定义的比较方法叫所有的时间的额外性能开销。

3

如果,你的问题意味着,你的兴趣只在由备用钥匙排序 namedtuples,为什么不使用排序/整理key参数与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)] 
+0

排序字段现在还不存在,所以我需要添加它或者使用一个cmp方法来查看2个字段并且对它们做一些逻辑(我的示例代码过于简化) – pfctdayelise