使python用户定义的类可排序,可哈希化


82

在python中使用户定义的类可排序和/或可哈希化时,需要重写/实现哪些方法?

需要注意的陷阱是什么?

我输入dir({})解释器以获取内置字典的方法列表。其中,我假设我需要一些实现

['__cmp__', '__eq__', '__ge__', '__gt__', '__hash__', '__le__', '__lt__', '__ne__']

与Python2相比,必须为Python3实现哪些方法有区别吗?


3
这里的讨论很好:stackoverflow.com/q/1061283/641766。Python 2.x和3.x之间的区别是__cmp__已删除。
zeekay 2011年

Answers:


88

我差点把它作为对其他答案的评论,但这本身就是一个答案。

为了使您的项目可排序,它们只需要实现__lt__。这是内置排序使用的唯一方法。

其他比较还是functools.total_ordering仅在您确实要对类使用比较运算符时才需要。

为了使您的项目可散列,请__hash__按照其他说明实施。您还应该__eq__以兼容的方式实现-等效的项目应使用相同的哈希值。


因此,糟糕的实现__lt__可能导致python发生不可预测的排序?(例如,如果x .__ lt __(y)和y .__ lt __(x))
Matt Fenwick

3
我不知道“不可预测的”,如果输入完全相同的输入将是一致的,但是不同的输入顺序可能导致不同的项目以不同的顺序排列。是的,如果您不正确地实现了用于排序的比较,Python将会不正确地进行排序。我建议使用一个__key__将实例转换为元组的函数,然后同时使用__lt__self.__key__() < other.__key__())和__hash__hash(self.__key__()))。
2011年

19

Python 2和3之间没有任何区别。

为了可分类性:

您应该定义比较方法。这使您的项目可排序。通常,您不应该首选__cmp__()

我通常使用functools.total_ordering装饰器。

functools.total_ordering(cls)给定一个定义了一个或多个丰富比较排序方法的类,该类装饰器提供其余的方法。这简化了指定所有可能的丰富比较操作的工作:

这个类必须定义之一__lt__()__le__()__gt__(),或 __ge__()。另外,该类应提供一个__eq__()方法。

您应该小心,比较方法不会有任何副作用。(更改对象的任何值)

对于散列:

您应该实现__hash__()方法。我认为最好的方法是返回hash(repr(self)),因此您的哈希将是唯一的。


有关functools.total_ordering文档的示例,请参见此处
Evgeni Sergeev'6

3

有几种标记对象可排序的方法。首先-丰富的比较,由一组函数定义:

object.__lt__(self, other)
object.__le__(self, other)
object.__eq__(self, other)
object.__ne__(self, other)
object.__gt__(self, other)
object.__ge__(self, other)

也可以只定义一个功能:

object.__cmp__(self, other)

如果要定义自定义__hash__函数,则应定义最后一个。参见文档


6
在Python 3中,“__cmp__()不再支持特殊方法”,请参见此处相关部分
Evgeni Sergeev'6

-3

实施__lt__(self,other)方法是使您的班级可排序的答案。
它不仅可以用于内置方法sorted(iterable),还可以用于通过heapq模块的优先级队列。

另外,我不喜欢python的设计,所以很多'__ge__', '__gt__', '__le__', '__lt__', '__ne__'方法根本都不直观
相反,Java Interface Comparable<T> (请参阅java doc)将返回负整数,零或正整数,因为此对象小于,等于或大于指定的对象,这是直接且友好的


9
您的大部分答案都涵盖了您的观点(这不应成为答案的一部分)。
凌晨

@skyking ...虽然我不同意这个特定答案中的观点,但我确实认为(带有与问题相关的研究和有用数据的观点)非常有价值。该意见答案中的错误不支持有关数据的意见。但是了解偏好有助于人们做出决定,因此非常有用。在这里,答案是错误的,因为没有有用且可操作的python代码来说明基于作者偏好的pythonic编码方法。
安德鲁
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.