2012-04-17 12 views
25

In Python 2.7, i dizionari hanno sia un metodo iterkeys sia un metodo viewkeys (e coppie simili per valori e voci), dando due modi diversi di scorrere lentamente le chiavi del dizionario. Il metodo viewkeys fornisce la funzione principale di iterkeys, con iter(d.viewkeys()) equivalente a d.iterkeys(). Inoltre, gli oggetti restituiti viewkeys dispongono di comode funzioni set-like. Esistono quindi forti motivi per favorire lo viewkeys su iterkeys.Per un dizionario Python, iterkeys offrono vantaggi rispetto ai viewkey?

E l'altra direzione? Oltre alla compatibilità con le versioni precedenti di Python, ci sono modi in cui iterkeys sarebbe preferibile a viewkeys? Sarebbe tutto perso semplicemente usando sempre viewkeys?

+2

* "Oltre alla compatibilità con le versioni precedenti di Python" * - la cosa è, è qualcosa che difficilmente si potrebbe chiamare irrilevante. Altrimenti, tutti useranno Python3.2 già – vartec

+4

@vartec Non è irrilevante, ma è ovvio. –

+0

ma poi di nuovo, a parte il fatto che 'iterkeys()' non ha vantaggio su 'viewkeys()'. – vartec

risposta

8

No, non c'è alcun vantaggio per iterkeys su viewkeys, allo stesso modo che non c'è alcun vantaggio su keys su uno di essi. iterkeys è disponibile solo per compatibilità retroattiva. Infatti, in Python 3, viewkeys è l'unico comportamento ancora esistente ed è stato rinominato in keys - il metodo è in realtà un backport del comportamento di Python 3.

+4

Questo non spiega nessuna delle differenze – SystemParadox

+5

@SystemParadox la domanda esplicitamente non chiede esattamente quali sono le differenze - OP chiede specificamente se c'è qualsiasi vantaggio nell'usare 'iter *' su 'view *', e * già elenca * i vantaggi nell'altra direzione. – lvc

21

Un dizionario visualizza gli aggiornamenti come il dizionario, mentre un iteratore non lo fa necessariamente.

Ciò significa che se si lavora con la vista, si modifica il dizionario, quindi si lavora di nuovo con la vista, la vista sarà cambiata per riflettere il nuovo stato del dizionario.

Forniscono una vista dinamica sulle voci del dizionario, il che significa che quando il dizionario cambia, la vista riflette queste modifiche. Source

Esempio:

>>> test = {1: 2, 3: 4} 
>>> a = test.iterkeys() 
>>> b = test.viewkeys() 
>>> del test[1] 
>>> test[5] = 6 
>>> list(a) 
[3, 5] 
>>> b 
dict_keys([3, 5]) 

Quando vengono apportate modifiche alle dimensioni, verrà generata un'eccezione:

>>> test = {1: 2, 3: 4} 
>>> a = test.iterkeys() 
>>> b = test.viewkeys() 
>>> test[5] = 6 
>>> list(a) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
RuntimeError: dictionary changed size during iteration 
>>> b 
dict_keys([1, 3, 5]) 

Vale anche la pena che si nota non può che iterare su una keyiterator volta :

>>> test = {1: 2, 3: 4} 
>>> a = test.iterkeys() 
>>> list(a) 
[1, 3] 
>>> list(a) 
[] 
>>> b = test.viewkeys() 
>>> b 
dict_keys([1, 3]) 
>>> b 
dict_keys([1, 3]) 
+2

Questo è tutto vero, ma in realtà non affronta la domanda - l'OP sa cosa 'viewkeys' fa, e si chiede specificatamente se ci siano degli svantaggi nel fingere che' iterkeys' non esista. – lvc

+2

@lvc Spiega le differenze, che possono essere considerate positive a '' iterkeys() '' - se, per esempio, non si vuole che si aggiorni, usando '' iterkeys() '' potrebbe essere più adatto (anche se la stessa funzionalità potrebbe essere creata con '' viewkeys() ''). Non sto dicendo che sia una ragione forte, ma è praticamente l'unica. –

+0

@larsmans Si potrebbe sostenere che è stato meglio che lavorare silenziosamente alla versione aggiornata in cui non si voleva, ma sono d'accordo che è un tratto. Sì, la risposta breve è che non c'è alcun motivo per usare '' iterkeys() '', che è il motivo per cui è andato in Python3.Tuttavia, ho pensato di spiegare le differenze nella speranza che rendesse chiara la distinzione. –

7

Come il nome (e documentation) indicano le viewkeys(), viewvalues() e viewitems() metodi restituiscono un vista degli elementi correnti nel dizionario significa che se le modifiche al dizionario, così fa la vista; le viste sonolazy. Nel caso generale le chiavi le viste sono impostate e le viste sono impostate come se i valori fossero selezionabili.

In quali casi sarebbe meglio utilizzare i metodi standard keys(), values() e items()? Hai menzionato un argomento molto importante: la retrocompatibilità. Inoltre, quando è necessario disporre di un semplice elenco di tutte le chiavi, valori o elementi (non un set-like, non un iteratore), quando è necessario modificare l'elenco restituito senza modificare il dizionario originale e quando è necessaria un'istantanea di un chiavi, valori o elementi del dizionario in un determinato momento, indipendentemente da eventuali modifiche posteriori sul dizionario.

E che dire di iterkeys(), itervalues() e iteritems()? Sono un'alternativa adatta quando hai bisogno di uno snapshot istantaneo, a spazio costante, lazy iterator dei contenuti di un dizionario che ti dirà se il dizionario è stato modificato durante l'iterazione (tramite un RuntimeError), anche loro sono molto importanti per il backwards Compatibilità.

+1

Non temo - ['(viste del dizionario) sono sequenze pigre'] (http://docs.python.org/glossary.html) –

+0

@Lattyware grazie, risolto. –

+1

Chiarimento minore: le viste delle voci sono impostate solo se i valori sono lavabili. –

12

In termini di funzionalità, come si è osservato, le visualizzazioni sono migliori. Per quanto riguarda la compatibilità, sono peggio.

Alcuni parametri di rendimento, prelevati da Python 2.7.2 su una macchina Ubuntu 64 bit:

>>> from timeit import timeit 

Trattare con un dizionario vuoto:

>>> emptydict = {} 
>>> timeit(lambda: emptydict.viewkeys()) 
0.24384498596191406 
>>> timeit(lambda: list(emptydict.viewkeys())) 
0.4636681079864502 
>>> timeit(lambda: emptydict.iterkeys()) 
0.23939013481140137 
>>> timeit(lambda: list(emptydict.iterkeys())) 
1.0098130702972412 

Costruire la vista è leggermente più costoso, ma consumare la vista è significativamente più veloce dell'iteratore (un po 'più del doppio della velocità).

Trattare con un dizionario mille-elemento:

>>> fulldict = {i: i for i in xrange(1000)} 
>>> timeit(lambda: fulldict.viewkeys()) 
0.24295306205749512 
>>> timeit(lambda: list(fulldict.viewkeys())) 
13.447425842285156 
>>> timeit(lambda: fulldict.iterkeys()) 
0.23759889602661133 
>>> timeit(lambda: list(fulldict.iterkeys())) 
15.45390510559082 

stessi risultati, anche se meno marcata; la costruzione della vista è leggermente più costosa, ma consumarla è decisamente più veloce (15% più veloce).

Per confronto equo con list(dict.viewkeys()) e list(dict.iterkeys()), dict.keys() è distinctlyfaster:

>>> timeit(lambda: emptydict.keys()) 
0.2385849952697754 
>>> timeit(lambda: fulldict.keys()) 
7.842105150222778 

Sommario: si tratta di un trade-off; migliore funzionalità (che userete raramente) e prestazioni (che sarà solo molto raramente essere abbastanza significativo da preoccuparvi — se vi preoccupate di tali prestazioni, probabilmente siete già nella regione di dover lavorare con numpy/scipy) rispetto a una migliore compatibilità e all'utilizzo della memoria muscolare.

Personalmente, a meno che non sia già in funzione sulla funzionalità solo 2.7 o se non sto controllando in modo assoluto l'ambiente di runtime, evito le visualizzazioni del dizionario nel codice Python 2. Anche in questi casi, le mie dita vogliono ancora digitare iter invece di view, quindi le lascio!

+0

Alcuni di noi vivono in anticipo sulla curva, so che per impostazione predefinita solo '' items() '' e gli amici grazie all'uso di Python 3.x molto. Devo fare attenzione quando torno a Python 2.x. Per essere onesti, mentre il supporto 3.x è una borsa mista, il supporto 2.7.3 è praticamente universale a questo punto, dare o prendere quello dispari. –

+0

@Lattyware: Non ho avuto questo problema perché non ho ancora usato Python 3 per nessun progetto (ancora dipendente da Python 2, ad esempio Django). –

+0

Siamo tutti vincolati dalle cose che usiamo. Capisco che Django si sta avvicinando alla piena compatibilità 3.x. Oh, e ho dimenticato di dire, +1 per l'analisi approfondita della velocità. –

Problemi correlati