在Python 3中使类可比的标准方法是什么? (例如,通过id。)
答案 0 :(得分:7)
sort
仅需__lt__
。
functools.total_ordering
(截至2.7 / 3.2)是一个提供所有比较运算符的装饰器,因此您不必自己编写所有这些运算符。
默认情况下,类是可清除的,并使用它们的id()
;我不确定你为什么要按id()
订购课程,除非你只是希望订单稳定。
答案 1 :(得分:6)
对于一整套比较函数,我使用了以下mixin,你可以在模块中输入一个mixin.py。
class ComparableMixin(object):
def _compare(self, other, method):
try:
return method(self._cmpkey(), other._cmpkey())
except (AttributeError, TypeError):
# _cmpkey not implemented, or return different type,
# so I can't compare with "other".
return NotImplemented
def __lt__(self, other):
return self._compare(other, lambda s, o: s < o)
def __le__(self, other):
return self._compare(other, lambda s, o: s <= o)
def __eq__(self, other):
return self._compare(other, lambda s, o: s == o)
def __ge__(self, other):
return self._compare(other, lambda s, o: s >= o)
def __gt__(self, other):
return self._compare(other, lambda s, o: s > o)
def __ne__(self, other):
return self._compare(other, lambda s, o: s != o)
要使用上面的mixin,您需要实现一个_cmpkey()方法,该方法返回可以比较的对象的键,类似于排序时使用的key()函数。实现可能如下所示:
>>> from .mixin import ComparableMixin
>>> class Orderable(ComparableMixin):
...
... def __init__(self, firstname, lastname):
... self.first = firstname
... self.last = lastname
...
... def _cmpkey(self):
... return (self.last, self.first)
...
... def __repr__(self):
... return "%s %s" % (self.first, self.last)
...
>>> sorted([Orderable('Donald', 'Duck'),
... Orderable('Paul', 'Anka')])
[Paul Anka, Donald Duck]
我使用它而不是total_ordering配方的原因是this bug。它已在Python 3.4中修复,但通常也需要支持较旧的Python版本。
答案 2 :(得分:0)
答案 3 :(得分:0)
你说你正试图这样做:
max((f(obj), obj) for obj in obj_list)[1]
你应该这样做:
max(f(obj) for obj in obj_list)
编辑:或者正如gnibbler所说:max(obj_list, key=f)
但是你告诉gnibbler你需要一个对象引用max对象。我认为这是最简单的:
def max_obj(obj_list, max_fn):
if not obj_list:
return None
obj_max = obj_list[0]
f_max = max_fn(obj)
for obj in obj_list[1:]:
if max_fn(obj) > f_max:
obj_max = obj
return obj_max
obj = max_obj(obj_list)
当然,如果您尝试查找空列表的max_obj(),您可能希望让它引发异常而不是返回任何异常。
答案 4 :(得分:0)
我只是想到了一种真正的hackish方式。这与您最初尝试的精神相同。它不需要向类对象添加任何函数;它适用于任何类。
max(((f(obj), obj) for obj in obj_list), key=lambda x: x[0])[1]
我真的不喜欢这样,所以这里有一些不那么简洁的东西:
def make_pair(f, obj):
return (f(obj), obj)
def gen_pairs(f, obj_list):
return (make_pair(f, obj) for obj in obj_list)
def item0(tup):
return tup[0]
def max_obj(f, obj_list):
pair = max(gen_pairs(f, obj_list), key=item0)
return pair[1]
或者,如果obj_list
始终是像列表一样的可索引对象,则可以使用此单行:
obj_list[max((f(obj), i) for i, obj in enumerate(obj_list))[1]]
这样做的好处是,如果有多个对象使f(obj)
返回相同的值,您就知道将获得哪一个:索引最高的那个,即列表中的最新一个。如果你想要列表中最早的那个,你可以用一个关键功能来做到这一点。