Pythonユーザー定義クラスをソート可能、ハッシュ可能にする


83

ユーザー定義クラスをPythonでソート可能および/またはハッシュ可能にする場合、どのメソッドをオーバーライド/実装する必要がありますか?

注意すべき落とし穴は何ですか?

dir({})インタプリタに入力して、組み込みのdictのメソッドのリストを取得します。それらのうち、私はいくつかのサブセットを実装する必要があると思います

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

Python2とは対照的にPython3に実装する必要のあるメソッドに違いはありますか?


3
ここで良い議論:stackoverflow.com/q/1061283/641766。Python 2.xと3.xの違いは、__cmp__削除されたことです。
zeekay 2011

回答:


90

私はこれを他の回答へのコメントとして投稿するところだったが、それ自体が実際の回答である。

アイテムを並べ替え可能にするには、を実装するだけで済みます__lt__。これは、組み込みの並べ替えで使用される唯一の方法です。

他の比較、またはfunctools.total_ordering実際にクラスで比較演算子を使用する場合にのみ必要です。

アイテムをハッシュ可能にするには__hash__、他の人が指摘したように実装します。また__eq__、互換性のある方法で実装する必要があります。同等のアイテムは同じハッシュにする必要があります。


の実装が不十分だ__lt__と、Pythonが予期せずソートされる可能性がありますか?(たとえば、x .__ lt __(y)およびy .__ lt __(x)の場合)
Matt Fenwick 2011

3
「予測できない」についてはわかりません。まったく同じ入力を入力しても一貫性がありますが、入力の順序が異なると、アイテムの順序が異なる可能性があります。はい、並べ替えに使用される比較を不適切に実装すると、Pythonは不適切に並べ替えます。__key__インスタンスをタプルに変換し、__lt__self.__key__() < other.__key__())と__hash__hash(self.__key__()))の両方にそれを使用させる関数をお勧めします。
agf 2011

21

Python2と3の間に違いはありません。

ソート可能性の場合:

比較方法を定義する必要があります。これにより、アイテムが並べ替え可能になります。一般的に、あなたは好むべきではありません__cmp__()

私は通常functools.total_orderingデコレータを使用します。

functools.total_ordering(cls)1つ以上の豊富な比較順序付けメソッドを定義するクラスが与えられると、このクラスデコレータが残りを提供します。これにより、可能なすべての豊富な比較操作を指定する作業が簡素化されます。

クラスは次のいずれかを定義しなければならない__lt__()__le__()__gt__()、または __ge__()。さらに、クラスは__eq__()メソッドを提供する必要があります。

比較方法に副作用がないように注意する必要があります。(オブジェクトの値のいずれかを変更します)

ハッシュの場合:

__hash__()メソッドを実装する必要があります。を返すのが最善の方法だと思うhash(repr(self))ので、ハッシュは一意になります。


functools.total_orderingドキュメントの例については、こちらを参照してください
Evgeni Sergeev 2016年

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)

また、1つの関数のみを定義することもできます。

object.__cmp__(self, other)

また、カスタム__hash__関数を定義する場合は、最後を定義する必要があります。ドキュメントを参照してください。


6
Python 3では、「[...]__cmp__()特別なメソッドはサポートされなくなりました。」関連するセクションを参照してください
Evgeni Sergeev 2016年

-3

実装__lt__(self,other)メソッドは、クラスをソート可能にするための答えです。
組み込み方式だけでなく、モジュールsorted(iterable)経由の優先キューにも使用できheapqます。

さらに、私はPythonのデザインが好きで'__ge__', '__gt__', '__le__', '__lt__', '__ne__'ないので、多くのメソッドはまったく直感的ではありません
対照的に、Java Interface Comparable<T>java docを参照)は、このオブジェクトが指定されたオブジェクトよりも小さい、等しい、または大きいため、負の整数、ゼロ、または正の整数を返します。これは直接的でわかりやすいです。


9
あなたの答えのほとんどはあなたの意見をカバーしています(それは答えの一部であってはなりません)。
スカイキング2018

@skyking ...この特定の回答の意見には同意しませんが、意見(質問に関連する調査済みの有用なデータを含む)は非常に価値があると思います。この意見回答の誤りは、関連データのある意見を裏付けるものではありません。しかし、好みを理解することは、人々が決定を下すのに役立つため、非常に役立ちます。ここでは、作成者の好みに基づいてPythonでコーディングする方法を説明するための、有用で実用的なPythonコードがないため、答えは正しくありません。
アンドリュー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.