John Millikin buna benzer bir çözüm önerdi:
class A(object):
def __init__(self, a, b, c):
self._a = a
self._b = b
self._c = c
def __eq__(self, othr):
return (isinstance(othr, type(self))
and (self._a, self._b, self._c) ==
(othr._a, othr._b, othr._c))
def __hash__(self):
return hash((self._a, self._b, self._c))
Bu çözüm ile ilgili sorun hash(A(a, b, c)) == hash((a, b, c))
. Başka bir deyişle, karma, anahtar üyelerinin demetininki ile çarpışır. Belki bu pratikte çok önemli değil?
Güncelleme: Python belgeleri şimdi yukarıdaki örnekte olduğu gibi bir demet kullanılmasını önermektedir. Belgelerin belirttiği gibi
Gereken tek özellik, eşitliği karşılaştıran nesnelerin aynı karma değerine sahip olmasıdır
Bunun tersinin doğru olmadığını unutmayın. Eşit karşılaştırılmayan nesneler aynı karma değerine sahip olabilir . Böyle bir karma çarpışma, dikte anahtarı veya set öğesi olarak kullanıldığında, nesneler de eşit olmadığı sürece bir nesnenin diğerinin yerini almasına neden olmaz .
Eski / kötü çözüm
Python belgelerine__hash__
XOR gibi bir şey kullanarak alt bileşenlerinin karmaları birleştirmek için önermektedir bu bizi veren:
class B(object):
def __init__(self, a, b, c):
self._a = a
self._b = b
self._c = c
def __eq__(self, othr):
if isinstance(othr, type(self)):
return ((self._a, self._b, self._c) ==
(othr._a, othr._b, othr._c))
return NotImplemented
def __hash__(self):
return (hash(self._a) ^ hash(self._b) ^ hash(self._c) ^
hash((self._a, self._b, self._c)))
Güncelleme: Blckknght'ın işaret ettiği gibi, a, b ve c sırasını değiştirmek sorunlara neden olabilir. ^ hash((self._a, self._b, self._c))
Karma olan değerlerin sırasını yakalamak için bir ek ekledim . Bu final ^ hash(...)
, birleştirilen değerler yeniden düzenlenemezse kaldırılabilir (örneğin, farklı türleri varsa ve bu nedenle değeri _a
hiçbir zaman _b
veya _c
, vb.'ye atanmayacaksa ).
__key
İşlevi çarpanlarına ayırmak için küçük ek yükün yanı sıra , bu herhangi bir karma olabildiğince hızlıdır. Tabii, özniteliklerin tamsayı olduğu biliniyorsa ve çok fazla yoksa, sanırım bazı evde haddelenmiş karma ile biraz daha hızlı çalışabilirsiniz , ancak muhtemelen iyi dağıtılmayacaktır. küçük s'lerin oluşturulması özel olarak optimize edildiğinden ve hashleri alma ve birleştirme işini genellikle Python seviye kodundan daha hızlı olan C yerleşiklerine itmehash((self.attr_a, self.attr_b, self.attr_c))
şaşırtıcı derecede hızlı (ve doğru ) olacaktırtuple
.