TL; DR:
Lütfen sözlüğe bakın : hash()
nesneleri karşılaştırmak için kısayol olarak kullanılır, bir nesne diğer nesnelerle karşılaştırılabiliyorsa hashable olarak kabul edilir. bu yüzden kullanıyoruz hash()
. Aynı zamanda erişmek için kullanılan dict
ve set
gibi uygulandığı elemanları CPython boyutlandırılabilir karma tablolar .
Teknik hususlar
- genellikle nesneleri karşılaştırmak (birkaç seviyede yineleme içerebilir) pahalıdır.
- tercihen,
hash()
işlev bir büyüklük (veya birkaç) mertebesinde daha ucuzdur.
- iki hash'i karşılaştırmak, iki nesneyi karşılaştırmaktan daha kolaydır, kısayolun olduğu yer burasıdır.
Sözlüklerin nasıl uygulandığını okursanız , karma tablolar kullanırlar; bu, bir nesneden bir anahtar türetmenin, sözlüklerdeki nesneleri almak için bir köşe taşı olduğu anlamına gelir O(1)
. Ancak bu, hash fonksiyonunuzun çarpışmaya dayanıklı olmasına çok bağlıdır . Bir öğeyi almak için en kötü durum bir sözlükte aslında O(n)
.
Bu notta, değişebilir nesneler genellikle hashable değildir. Hashable özelliği, bir nesneyi anahtar olarak kullanabileceğiniz anlamına gelir. Karma değeri bir anahtar olarak kullanılırsa ve aynı nesnenin içeriği değişirse, karma işlevi ne döndürmelidir? Aynı anahtar mı yoksa farklı mı? Bu bağlıdır Eğer karma işlevi nasıl tanımladığına.
Örnek olarak öğrenmek:
Bu sınıfa sahip olduğumuzu hayal edin:
>>> class Person(object):
... def __init__(self, name, ssn, address):
... self.name = name
... self.ssn = ssn
... self.address = address
... def __hash__(self):
... return hash(self.ssn)
... def __eq__(self, other):
... return self.ssn == other.ssn
...
Lütfen dikkat: Bunların tümü, SSN'nin bir birey için asla değişmediği varsayımına dayanmaktadır (bu gerçeği yetkili kaynaktan gerçekten nerede doğrulayacağınızı bile bilmiyorum).
Ve bizde Bob var:
>>> bob = Person('bob', '1111-222-333', None)
Bob, ismini değiştirmek için bir yargıca gider:
>>> jim = Person('jim bo', '1111-222-333', 'sf bay area')
Bildiğimiz bu:
>>> bob == jim
True
Ancak bunlar, aynı kişinin iki farklı kaydı gibi, ayrılmış farklı belleğe sahip iki farklı nesnedir:
>>> bob is jim
False
Şimdi hash () işlevinin kullanışlı olduğu kısım geliyor:
>>> dmv_appointments = {}
>>> dmv_appointments[bob] = 'tomorrow'
Bil bakalım ne oldu:
>>> dmv_appointments[jim]
'tomorrow'
İki farklı kayıttan aynı bilgilere erişebilirsiniz. Şimdi şunu dene:
>>> dmv_appointments[hash(jim)]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 9, in __eq__
AttributeError: 'int' object has no attribute 'ssn'
>>> hash(jim) == hash(hash(jim))
True
Az önce ne oldu? Bu bir çarpışma. Çünkü hash(jim) == hash(hash(jim))
hangi ikisi tamsayılar btw biz girişini karşılaştırmak gerekir şunlardır __getitem__
çarpmasıyla, tüm öğeleri ile. Yerleşik int
bir ssn
niteliğe sahip değildir, bu nedenle tökezler.
>>> del Person.__eq__
>>> dmv_appointments[bob]
'tomorrow'
>>> dmv_appointments[jim]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: <__main__.Person object at 0x7f611bd37110>
Bu son örnekte, bir çarpışmada bile karşılaştırmanın yapıldığını, nesnelerin artık eşit olmadığını, yani başarılı bir şekilde a yükselttiğini gösteriyorum KeyError
.