Python:用__cmp__对句子进行排序,其中__lt__表示"严格小于"

时间:2014-12-11 00:40:29

标签: python python-2.7 sorting operators

我有一个intervaltree库,需要对Intervals进行排序,最后Points

我有一个__cmp__方法,它强加了非常稳定和逻辑的排序(参见代码的结尾)。而且,我有一个有用的__lt__方法来查看间隔是否严格小于彼此(同上)。

我对这种行为进行了大约30次测试,这很好......

问题

......除非我需要排序:

>>> sorted([Interval(0, 10), Interval(-10, 5)])
[Interval(0, 10), Interval(-10, 5)]               # WRONG!

因为Python使用__lt__,所以它使用"严格小于"语义而不是__cmp__。我可以强制它明确地这样做,但我宁愿避免使用繁琐的语法:

>>> sorted([Interval(0, 10), Interval(-10, 5)], cmp=Interval.__cmp__)
[Interval(-10, 5), Interval(0, 10)]               # RIGHT

在Python 3中,语法更加繁琐(Python 2.6中不可用,Python 2.7中提供)。

>>> from functools import cmp_to_key
>>> sorted([Interval(0, 10), Interval(-10, 5)], key=cmp_to_key(Interval.__cmp__))

我想要什么

我有没有办法让sorted()和朋友自动使用Interval.__cmp__,但仍保持__lt__原样?也就是说,我想要这种优雅的行为:

>>> sorted([Interval(0, 10), Interval(-10, 5)])   # no extra arguments!
[Interval(-10, 5), Interval(0, 10)]

附录:__cmp____lt__

的实施
def __cmp__(self, other):
    """
    Tells whether other sorts before, after or equal to this
    Interval.

    Sorting is by begins, then by ends, then by data fields.

    If data fields are not both sortable types, data fields are
    compared alphabetically by type name.
    :param other: Interval
    :return: -1, 0, 1
    :rtype: int
    """
    s = self[0:2]
    try:
        o = other[0:2]
    except:
        o = (other,)
    if s != o:
        return -1 if s < o else 1
    try:
        if self.data == other.data:
            return 0
        return -1 if self.data < other.data else 1
    except TypeError:
        s = type(self.data).__name__
        o = type(other.data).__name__
        if s == o:
            return 0
        return -1 if s < o else 1

def __lt__(self, other):
    """
    Less than operator. Returns False if there is an overlap.
    :param other: Interval or point
    :return: True or False
    :rtype: bool
    """
    return not self.overlaps(other) and self.end <= other

PS:这个问题出现在开发分支中,我希望将__lt__的行为改为&#34;严格小于。&#34;在主分支(版本1.1.0)中,__lt__只是鹦鹉__cmp__

更新

  • (2014-12-12): 现在,在我的开发分支中,我提供Interval.sortedInterval.key。尽管如此,仍然不那么优雅。我还在寻找更好的方法!

1 个答案:

答案 0 :(得分:3)

我强烈建议不要为您的班级定义任何订单运算符

原因是订单运算符的存在意味着存在一个顺序关系及其相关的语义,这是你的类本身违反的(在间隔上没有明确定义的顺序关系)。

例如,订单关系意味着:

not(a<b) and not(b<a) ==> a==b

间隔时间不是这样。

换句话说,你不应该只是决定你希望你的运算符是什么意思(例如__lt__意味着 strict 小于),语义是在语言中预先定义的你(例如sorted的实现依赖于那个语义)。

您应该做的是定义用于比较的非运算符方法(例如def strict_lt(self, other): ...),并使用它们。我还定义了sort_intervals函数,并在代码中直接使用它而不是sorted。 E.g:

def sort_intervals(lst):
    return sorted(lst, cmp = ...)