web-dev-qa-db-ja.com

heapq Push TypeError: '<'インスタンス間ではサポートされていません

pythonで作業していますが、heapqに問題があります。要素をヒープにプッシュすると、次のエラーが発生します。

TypeError: '<'は 'Point'と 'Point'のインスタンス間ではサポートされていません

ポイントは私の内部クラスです。 (float、Point)によって形成されたタプルをプッシュします。ドキュメントによると、heapqはfloatをキーとして使用する必要がありますが、そうではありません。より正確に言うと、floatを使用することもありますが、常にそうとは限りません。何が問題ですか?

5
Francesco

heapqは、入力したものに_<=_演算子を使用します。

タプルは位置ごとに比較されます。最初のタプルの最初のアイテムが2番目のタプルの最初のアイテムと比較されます。それらが等しくない場合(つまり、最初の項目が2番目の項目よりも大きいか小さい場合)、それは比較の結果です。そうでない場合は、2番目の項目が考慮され、次に3番目の項目が考慮されます。

各タプルの最初のアイテムが一意である場合、比較は常に最初のアイテムでのみ行われます。

_>>> x = (1, object())
>>> y = (2, object())
>>> x <= y
True
_

(注:object()を使用して、比較演算子を実装しない匿名オブジェクトを作成しました)

この問題は、タプルの最初のアイテムが一意でない場合(つまり、最初のタプルアイテムがタプルのペアごとに等しくなる場合)に発生します。比較では、タプルの2番目のアイテムを比較する必要があります。

_>>> z = (1, object())
>>> x <= z
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    x <= z
TypeError: '<=' not supported between instances of 'object' and 'object'
_

したがって、オブジェクトに比較演算子を実装するか、タプル内の先行する項目が常に比較可能であり、一緒に一意であることを確認します。

たとえば、オブジェクトのIDをタプルに追加して、タプルが次のようになるようにすることができます。

_(priority, id(obj), obj)
_

オブジェクトIDは一意であるため。 (注意:同じ優先度で同じオブジェクトの2つのインスタンスを追加すると、この問題が再び発生します)。

8
fferri

Pointクラスで相対比較演算を定義する必要があります。これの意味は:

__lt__(self, other) for _<_

__le__(self,other) for _<=_

およびオプションで

__gt__(self, other) for _>_

__ge__(self, other) for _>=_。

指定しない場合、leltの否定が行われるため、最後の2つはオプションです。

これらのメソッドの一般的な構造は__name__(self, other)です。ここで、otherselfと比較されるオブジェクトです。また、TrueまたはFalseを返します。

上記の4つすべての代わりに___eq___を定義することもできます。これは、Javaのコンパレータのように機能します。このメソッドは、selfotherより大きい場合は正の整数を返し、等しい場合は0を返し、otherselfより大きい場合は負の整数を返します。

2
Michal Polovka