使 python 用户定义的类可排序、可散列

Posted

技术标签:

【中文标题】使 python 用户定义的类可排序、可散列【英文标题】:Making a python user-defined class sortable, hashable 【发布时间】:2011-11-01 10:09:03 【问题描述】:

在 python 中使用户定义的类可排序和/或可散列时需要覆盖/实现哪些方法?

有哪些注意事项?

我在解释器中输入dir() 以获取内置字典的方法列表。其中,我认为我需要实现一些子集

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

对于 Python3 和 Python2 必须实现哪些方法有区别吗?

【问题讨论】:

很好的讨论在这里:***.com/q/1061283/641766。 Python 2.x 和 3.x 的区别在于 __cmp__ 被删除了。 【参考方案1】:

我几乎将此作为对其他答案的评论发布,但它本身就是一个答案。

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

仅当您确实想在您的类中使用比较运算符时才需要其他比较或functools.total_ordering

为了使您的项目可散列,您实现 __hash__ 就像其他人指出的那样。您还应该以兼容的方式实现__eq__ - 等效项应该具有相同的哈希值。

【讨论】:

所以__lt__ 的糟糕实现可能会导致python 无法预测地排序? (例如,如果 x.__lt__(y) 和 y.__lt__(x)) 我不知道“不可预测”,如果输入完全相同的输入会保持一致,但不同的输入顺序可能会导致不同的项目处于不同的顺序。是的,如果您不正确地实现用于排序的比较,Python 将不正确地排序。我建议使用 __key__ 函数将实例转换为元组,然后同时使用 __lt__ (self.__key__() < other.__key__()) 和 __hash__ (hash(self.__key__()))。【参考方案2】:

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

为了便于排序:

您应该定义比较方法。这使您的项目可排序。一般来说,你不应该更喜欢__cmp__()

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

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

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

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

对于散列:

你应该实现__hash__() 方法。我认为最好的方法是返回hash(repr(self)),这样你的哈希值就会是唯一的。

【讨论】:

有关文档中functools.total_ordering 的示例,请参阅here。【参考方案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__ 函数,则应定义最后一个。请参阅doc。

【讨论】:

在 Python 3 中,“[...]__cmp__() 特殊方法不再受支持”,请参阅relevant section here。【参考方案4】:

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

另外,我不喜欢python的设计,这么多'__ge__', '__gt__', '__le__', '__lt__', '__ne__'方法一点都不直观! 作为对比,Java 的Interface Comparable<T>(参见java doc)返回负整数、零或正整数,因为该对象小于、等于或大于指定的对象,直接友好

【讨论】:

您的大部分回答都涵盖了您的意见(不应成为回答的一部分)。 @skyking ...虽然我不同意这个特定答案中的观点,但我确实相信观点(与问题相关的研究和有用的数据)非常有价值。该意见答案中的错误不支持相关数据的意见。但了解偏好有助于人们做出决定,因此非常有用。在这里,答案是错误的,因为没有有用且可操作的 Python 代码来说明基于作者偏好的 Python 编码方式。 @Andrew 除了这个观点完全不相关,因为问题是关于 python 的。当问题是关于 python 时,没有必要告诉 java 更好,而不是“哪种语言更好?”。它几乎是在讨论“什么是野兽编程语言?”这个永无止境的毫无意义的争论。对这个问题毫无用处。

以上是关于使 python 用户定义的类可排序、可散列的主要内容,如果未能解决你的问题,请参考以下文章

Swift 5.+ - 使类可散列?

自动使类可散列

是啥让用户定义的类不可散列?

具有可互换属性的可散列结构?

按值排序python集列表

Python @property