3

オブジェクトが を実装している場合、__hash__()特定の Python オブジェクトのストックを作成する一般的かつ迅速な方法は、 です。しかし、これは効率的ですか?this SO answerによると、オブジェクトの属性のタプルのハッシュは「適切」ですが、Python にとって最も効率的かどうかを示しているようには見えません。それとも、 for each オブジェクトを実装し、このページの実際のハッシュ アルゴリズムを使用して、個々の属性の値を によって返される最終的な値に混ぜ合わせた 方がよいでしょうか?return hash(str(self))__str__()__hash__()__hash__()

この SO questionから Jenkins ハッシュ ルーチンを実装したふりをします。どちら__hash__()を使うのが良いでしょうか?:

# hash str(self)
def __hash__(self):
    return hash(str(self))

# hash of tuple of attributes
def __hash__(self):
    return hash((self.attr1, self.attr2, self.attr3,
                 self.attr4, self.attr5, self.attr6))

# jenkins hash
def __hash__(self):
    from jenkins import mix, final
    a = self.attr1
    b = self.attr2
    c = self.attr3
    a, b, c = mix(a, b, c)
    a += self.attr4
    b += self.attr5
    c += self.attr6
    a, b, c = final(a, b, c)
    return c


簡単にするために、サンプル オブジェクトの属性はすべて整数であると仮定します。また、すべてのオブジェクトが基底クラスから派生し、各オブジェクトが独自の を実装していると仮定します__str__()。最初のハッシュを使用する場合のトレードオフは、それを基本クラスにも実装でき、各派生オブジェクトに追加のコードを追加しないことです。しかし、2 番目または 3 番目の__hash__()実装が何らかの点で優れている場合、各派生オブジェクトに追加されたコードのコストが相殺されるでしょうか (それぞれが異なる属性を持つ可能性があるため)。



編集:import 3 番目の実装にあるの__hash__()は、サンプル モジュール + オブジェクト全体を下書きしたくなかったからです。import関数の呼び出しごとではなく、モジュールの先頭で実際に発生すると仮定します。



結論:このクローズド SO questionに対する回答とコメントによると、速度や効率のためではなく、 と の根底にある二重性__hash__のために、タプル ハッシュの実装が本当に必要なようです__eq__。ハッシュ値の範囲は何らかの形式 (たとえば、32 ビットまたは 64 ビット) に制限されるため、ハッシュ衝突が発生した場合は、オブジェクトの等価性がチェックされます。したがって、__eq__()自己/他者の属性のタプル比較を使用してオブジェクトごとに実装__hash__()するので、物事のハッシュ/等価性を尊重するために、属性タプルを使用して実装したいと考えています。

4

1 に答える 1

3

2 番目のものには重要なパフォーマンスのペシミゼーションがあります。関数が呼び出されるたびに 2 つの名前をインポートしています。もちろん、文字列ハッシュ バージョンと比較してどの程度パフォーマンスが高いかは、文字列がどのように生成されるかによって異なります。

つまり、オブジェクトの等価性を定義する属性があり、それらの属性自体がハッシュ可能な型である場合、最も単純な (そしてほぼ確実に最適な) アプローチは、それらの属性値を含むタプルをハッシュすることです。

def __hash__(self):
    return hash((self.attr1, self.attr2, self.attr3))
于 2013-01-18T00:42:25.710 に答える