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

Making a python user-defined class sortable, hashable

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

你要注意什么?

我在解释器中键入dir({})以获得内置dict的方法列表。其中,我假设我需要实现

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

与python2相比,python3必须实现哪些方法有区别吗?


我几乎把它作为评论贴在其他答案上,但它本身就是一个答案。

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

其他比较或functools.total_ordering仅在您实际希望将比较运算符用于类时才需要。

为了使您的项目可以散列,您可以实现其他人提到的__hash__。您还应该以兼容的方式实现__eq__——等价项应该散列相同的内容。


python2和3没有任何区别。

对于可排序性:

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

我通常使用functools.total_订购装饰器。

functools.total_ordering(cls) Given a class defining one or more rich
comparison ordering methods, this class decorator supplies the rest.
This simplifies the effort involved in specifying all of the possible
rich comparison operations:

The class must define one of __lt__(), __le__(), __gt__(), or
__ge__(). In addition, the class should supply an __eq__() method.

你应该小心你的比较方法有副作用。在进行比较时,不希望更改类。

散列:

您应该实现__hash__()方法。我认为最好的方法是返回hash(repr(self)),这样您的散列将是唯一的。


有几种方法可以将对象标记为可排序。第一个丰富的比较,由一组函数定义:

1
2
3
4
5
6
object.__lt__(self, other)
object.__le__(self, other)
object.__eq__(self, other)
object.__ne__(self, other)
object.__gt__(self, other)
object.__ge__(self, other)

此外,也可以只定义一个函数:

1
object.__cmp__(self, other)

如果要定义自定义__hash__函数,则应定义最后一个函数。看医生。


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

另外,我不喜欢python的设计,所以很多'__ge__', '__gt__', '__le__', '__lt__', '__ne__'方法根本不直观!作为对比,Java的EDCOX1×12(参见Java DOC)返回负整数、零或正整数,因为这个对象小于、等于或大于指定的对象,这是直接和友好的!