我有一个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__
。
Interval.sorted
和Interval.key
。尽管如此,仍然不那么优雅。我还在寻找更好的方法!答案 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 = ...)