Un dizionario Python è un esempio di una tabella hash?


187

Una delle strutture di dati di base in Python è il dizionario, che consente di registrare "chiavi" per cercare "valori" di qualsiasi tipo. Questo è implementato internamente come una tabella hash? Se no, cos'è?


2
Se sei interessato ai dettagli tecnici, un articolo in Beautiful Code tratta gli interni dell'implementazione di Python dict.
Torsten Marek,

Quello era uno dei miei capitoli preferiti in Beautiful Code.
DGentry,

4
Ecco un discorso di Brandon Craig Rhodes che parla del funzionamento del dizionario Python, youtube.com/watch?v=C4Kc8xzcA68 .
chandola,

Ho cercato un diagramma che rappresentasse un dict per un po 'di tempo, che decifra l'implementazione in memoria e CPython. Grazie per aver fatto riferimento al libro!
Chen A.

Risposte:


241

Sì, è una mappatura hash o una tabella hash. Puoi leggere una descrizione dell'implementazione del dict di Python, come scritto da Tim Peters, qui .

Ecco perché non puoi usare qualcosa di "non cancellabile" come chiave dict, come un elenco:

>>> a = {}
>>> b = ['some', 'list']
>>> hash(b)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: list objects are unhashable
>>> a[b] = 'some'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: list objects are unhashable

Puoi leggere di più sulle tabelle di hash o controllare come è stato implementato in Python e perché è implementato in quel modo .


1
Le giunzioni dei collegamenti Tim Peters devono essere interrotte, esiste un collegamento pulito là fuori?
Matt Alcock,

1
@MattAlcock: ho aggiornato il link. A volte (di solito a causa di qualcuno che desidera che il proprio indirizzo e-mail venga rimosso da qualche parte), gli archivi dell'elenco Python vengono ricostruiti e gli ID delle e-mail cambiano, interrompendo così questi collegamenti. Gli amministratori di pydotorg generalmente cercano di evitarlo in questi giorni.
Martijn Pieters

Ma l'utilizzo .keys()può recuperare un elenco di chiavi. Una vera tabella hash non memorizzava le chiavi, solo hash per risparmiare spazio.
noɥʇʎԀʎzɐɹƆ

Descrizione più completa dell'implementazione di Python Dict
Daniel Goldfarb,

@ noɥʇʎԀʎzɐɹƆ: la chiave stessa non è memorizzata, ma solo un riferimento ad essa e all'hash.
nosklo

32

In un dizionario Python deve esserci più di una ricerca di tabella su hash (). Con la sperimentazione brutale ho trovato questa collisione di hash :

>>> hash(1.1)
2040142438
>>> hash(4504.1)
2040142438

Eppure non rompe il dizionario:

>>> d = { 1.1: 'a', 4504.1: 'b' }
>>> d[1.1]
'a'
>>> d[4504.1]
'b'

Controllo sanitario:

>>> for k,v in d.items(): print(hash(k))
2040142438
2040142438

Forse c'è un altro livello di ricerca oltre hash () che evita le collisioni tra le chiavi del dizionario. O forse dict () usa un hash diverso.

(A proposito, questo in Python 2.7.10. Stessa storia in Python 3.4.3 e 3.5.0 con una collisione a hash(1.1) == hash(214748749.8).)


14
Quindi le collisioni sono inevitabili. Set S può contenere un numero infinitamente elevato di elementi e si desidera che abbia l'hash su un numero che un computer può memorizzare. Ogni implementazione utilizzabile di una tabella hash risolve le collisioni, con due dei metodi più frequenti sono a) indirizzamento aperto eb) concatenamento. Solo perché non utilizza un hash perfetto non significa che non sia una tabella hash.
TurnipEntropy,

1
Le collisioni avvengono in generale, perché ci sono infiniti possibili valori hash e codici hash finiti. Anche una tabella di hash dovrebbe in qualche modo gestire la collisione.
Yanfeng Liu,

3
@YanfengLiu Credo che siano esattamente gli stessi punti fatti da TurnipEntropy.
Bob Stein,

1
In Python 3.7, sembra che ci siano 2E20 meno 1 possibili valori di hash, in effetti. Da -1E20 meno 1 a (+) 1E20 meno 1. Prova hash('I wandered lonely as a cloud, that drifts on high o\'er vales and hills, when all at once, I saw a crowd, a host of golden daffodils.')Questo dà un decimale di 19 cifre - -4037225020714749784se sei abbastanza geniale da preoccupartene. Continua con parole tue, figli, e l'hash è ancora un numero di 19 cifre. Suppongo che ci sia un limite alla lunghezza della stringa che puoi avere in Python, ma è sicuro di dire molte più stringhe possibili che possibili valori. E hash(False)= 0 a proposito.
Will Croxford,


7

Per espandere la spiegazione di nosklo:

a = {}
b = ['some', 'list']
a[b] = 'some' # this won't work
a[tuple(b)] = 'some' # this will, same as a['some', 'list']
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.