在实现类的__eq__和__lt__方法时,通常的做法是使用元组对要比较的值进行分组,如下所示:
@total_ordering
class Foo(object):
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
def __hash__(self):
return hash((self.c, self.a, self.b))
def __eq__(self, other):
return (self.c, self.a, self.b) == (other.c, other.a, other.b)
def __lt__(self, other):
return (self.c, self.a, self.b) < (other.c, other.a, other.b)
Run Code Online (Sandbox Code Playgroud)
然而,这使用了每个键的自然顺序。如果我想改变,例如,如何a排序?
到目前为止,这是我想出的,虽然它似乎工作正常,但我想知道是否有更好的方法来解决它:
@total_ordering
class Foo(object):
def __init__(self, a, b, c):
self.a = MyA(a) # Note
self.b = b
self.c = c
def __hash__(self):
return hash((self.c, self.a, self.b))
def __eq__(self, other):
return (self.c, self.a, self.b) == (other.c, other.a, other.b)
def __lt__(self, other):
return (self.c, self.a, self.b) < (other.c, other.a, other.b)
class MyA(A):
def __hash__(self):
# ...
def __eq__(self, other):
# ...
def __lt__(self, other):
# ...
Run Code Online (Sandbox Code Playgroud)
子类化A让我可以定义我的自定义排序,并允许MyA以A其他方式表现得像一个普通的,这很好,但它似乎很浪费/不必要的冗长,尤其是如果我必须对多个字段执行此操作。
编辑:根据下面 user1320237 的回答,这就是我想出的:
@total_ordering
class Foo(object):
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
def __hash__(self):
return hash((self.c, self.a, self.b))
def __eq__(self, other):
return (0, 0, 0) == (cmp(self.c, other.c),
cmpA(self.a, other.a),
cmp(self.b, other.b))
def __lt__(self, other):
return (0, 0, 0) > (cmp(self.c, other.c),
cmpA(self.a, other.a),
cmp(self.b, other.b))
def cmpA(a1, a2):
# ...
Run Code Online (Sandbox Code Playgroud)
(注意>in__lt__因为cmp(x, y)返回-1if x < yand __lt__should return True)
例如,如果您想使用 list.sort() 进行排序,您可以将参数传递给它:
您的代码:
...
def __lt__(self, other):
return (self.c, self.a, self.b) < (other.c, other.a, other.b)
...
list.sort()
Run Code Online (Sandbox Code Playgroud)
相等的:
list.sort(key = lambda self: (self.c, self.a, self.b))
Run Code Online (Sandbox Code Playgroud)
也等价:
list.sort(cmp = lambda self, other: \
(self.c, self.a, self.b) < (other.c, other.a, other.b))
Run Code Online (Sandbox Code Playgroud)
所以如果你想以不同的方式对你的答案进行排序,我会建议:
class Foo(object):
@staticmethod
def cmp_absoluteOrder(self, other):
return (self.c, self.a, self.b) < (other.c, other.a, other.b)
@staticmethod
def cmp_otherOrder(self, other):
return ...
@staticmethod
def cmp_combinedSort(cmpA, cmpB, cmpC):
return lambda self, other: (0, 0, 0) < (cmpA(self.c, other.c), cmpA(self.a, other.a), cmpA(self.b, other.b), )
def __hash__(self):
return hash(self.c) ^ hashA(self.a) ^ hash(self.b)
...
list.sort(cmp = Foo.cmp_absoluteSorting)
list.sort(cmp = Foo.cmp_combinedSort(cmp, (lambda a1, a2: ...), cmp))
hashA = hash # or replace it if important # but the same a will retunrn the same hash
Run Code Online (Sandbox Code Playgroud)
或类似的东西