在Python中定义用户自定义类使其可排序和/或可哈希时,需要重写/实现哪些方法?
需要注意哪些陷阱?
我在解释器中键入dir({})
以获取内置字典的方法列表。其中,我假设需要实现其中的一些子集。
['__cmp__', '__eq__', '__ge__', '__gt__', '__hash__', '__le__', '__lt__', '__ne__']
Python3和Python2在需要实现哪些方法方面有区别吗?
在Python中定义用户自定义类使其可排序和/或可哈希时,需要重写/实现哪些方法?
需要注意哪些陷阱?
我在解释器中键入dir({})
以获取内置字典的方法列表。其中,我假设需要实现其中的一些子集。
['__cmp__', '__eq__', '__ge__', '__gt__', '__hash__', '__le__', '__lt__', '__ne__']
Python3和Python2在需要实现哪些方法方面有区别吗?
我差点把这个作为对其他答案的评论,但它本身就是一个答案。
要使你的项可排序,它们只需要实现__lt__
方法。这是内置排序所使用的唯一方法。
其他比较或functools.total_ordering
只有在实际想要使用比较运算符与类一起使用时才需要。
要使您的项可哈希,您需要像其他人指出的那样实现__hash__
。您还应以兼容的方式实现__eq__
-- 相等的项应该具有相同的哈希值。
__lt__
实现可能会导致Python排序不可预测吗?(例如,如果x.lt(y)和y.lt(x)) - Matt Fenwick__key__
函数将实例转换为元组,然后让__lt__
(self.__key__() < other.__key__()
)和__hash__
(hash(self.__key__())
)都使用这个函数。 - agfPython 2和3之间没有任何区别。
为了排序:
你应该定义比较方法。这使得你的项目可以进行排序。通常情况下,不应该使用__cmp__()
。
我通常使用functools.total_ordering装饰器。
functools.total_ordering(cls) 给定一个定义了一个或多个丰富比较排序方法的类,此类装饰器提供其余部分。 这简化了指定所有可能丰富比较操作所涉及的工作:
该类必须定义
__lt__()
、__le__()
、__gt__()
或__ge__()
中的一个。此外,该类应提供一个__eq__()
方法。
你应该注意你的比较方法没有任何副作用(即不改变对象中的任何值)。
为了哈希:
你应该实现__hash__()
方法。我认为最好的方法是返回hash(repr(self))
,这样你的哈希将是唯一的。
id(self)
哈希值,因为它将是本地内存位置。这是一个快速且基本稳定的哈希,实现了哈希,以便如果对象是另一个对象,则哈希相同,否则不同。 - Tatarize有几种方法可以标记您的对象可排序。首先是通过一组函数定义的丰富比较:
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__
函数,可以定义最后一个参数。请参阅文档。
实现__lt__(self,other)
方法是使您的类可排序的答案。
它不仅可以用于内置方法sorted(iterable)
,还可以通过heapq
模块用于优先队列。
此外,我不喜欢Python的设计,太多的'__ge__', '__gt__', '__le__', '__lt__', '__ne__'
方法一点也不直观!
相比之下,Java的Interface Comparable<T>
(请参见java doc)返回负整数、零或正整数,表示此对象小于、等于或大于指定对象,这是直接和友好的!
__cmp__
。 - Zach Kelling