Risposte:
in
è decisamente più pitonico.
Infatti has_key()
è stato rimosso in Python 3.x .
keys()
è solo una vista simile a un set in un dizionario piuttosto che una copia, così x in d.keys()
è O (1). Tuttavia, x in d
è più Pythonic.
x in d.keys()
deve costruire e distruggere un oggetto temporaneo, completo dell'allocazione di memoria che comporta, in cui x in d.keys()
sta semplicemente facendo un'operazione aritmetica (calcolando l'hash) e facendo una ricerca. Si noti che d.keys()
è solo circa 10 volte più lungo di questo, il che non è ancora lungo. Non ho controllato ma sono ancora abbastanza sicuro che sia solo O (1).
in
vince a mani basse, non solo nell'eleganza (e non essendo deprecato ;-) ma anche nelle prestazioni, ad esempio:
$ python -mtimeit -s'd=dict.fromkeys(range(99))' '12 in d'
10000000 loops, best of 3: 0.0983 usec per loop
$ python -mtimeit -s'd=dict.fromkeys(range(99))' 'd.has_key(12)'
1000000 loops, best of 3: 0.21 usec per loop
Mentre la seguente osservazione non è sempre vera, noterai che di solito , in Python, la soluzione più veloce è più elegante e Pythonic; ecco perché -mtimeit
è così utile - non si tratta solo di salvare un centinaio di nanosecondi qua e là! -)
has_key
sembra essere anche O (1).
Secondo i documenti di Python :
has_key()
è deprecato a favore dikey in d
.
has_key()
viene ora rimosso in Python 3
Utilizzare dict.has_key()
se (e solo se) il codice deve essere eseguibile dalle versioni di Python precedenti alla 2.3 (quando è key in dict
stato introdotto).
C'è un esempio in cui in
uccide effettivamente la tua performance.
Se si utilizza in
su un contenitore O (1) che implementa solo __getitem__
e has_key()
non __contains__
trasformerà una ricerca O (1) in una ricerca O (N) (poiché in
ricade in una ricerca lineare tramite__getitem__
).
La correzione è ovviamente banale:
def __contains__(self, x):
return self.has_key(x)
has_key()
è specifico per i dizionari Python 2 . in
/ __contains__
è l'API corretta da utilizzare; per quei contenitori in cui è inevitabile una scansione completa, non esiste comunque alcun has_key()
metodo e se esiste un approccio O (1), sarà specifico del caso d'uso e quindi fino allo sviluppatore scegliere il giusto tipo di dati per il problema.
has_key
è un metodo di dizionario, ma in
funzionerà su qualsiasi raccolta e anche quando __contains__
manca, in
utilizzerà qualsiasi altro metodo per iterare la raccolta per scoprirlo.
in
test sugli range
oggetti. Non sono così sicuro della sua efficienza su Python 2 xrange
, però. ;)
__contains__
può banalmente calcolare se un valore è compreso nell'intervallo o meno.
range
istanza ogni volta. Utilizzando una singola istanza preesistente , il test "integer in range" è circa il 40% più veloce nei miei tempi.
La soluzione a dict.has_key () è obsoleta, usa 'in' - editor di testo sublime 3
Qui ho preso un esempio di dizionario chiamato 'age' -
ages = {}
# Add a couple of names to the dictionary
ages['Sue'] = 23
ages['Peter'] = 19
ages['Andrew'] = 78
ages['Karren'] = 45
# use of 'in' in if condition instead of function_name.has_key(key-name).
if 'Sue' in ages:
print "Sue is in the dictionary. She is", ages['Sue'], "years old"
else:
print "Sue is not in the dictionary"
Ampliamento dei test prestazionali di Alex Martelli con i commenti di Adam Parkin ...
$ python3.5 -mtimeit -s'd=dict.fromkeys(range( 99))' 'd.has_key(12)'
Traceback (most recent call last):
File "/usr/local/Cellar/python3/3.5.2_3/Frameworks/Python.framework/Versions/3.5/lib/python3.5/timeit.py", line 301, in main
x = t.timeit(number)
File "/usr/local/Cellar/python3/3.5.2_3/Frameworks/Python.framework/Versions/3.5/lib/python3.5/timeit.py", line 178, in timeit
timing = self.inner(it, self.timer)
File "<timeit-src>", line 6, in inner
d.has_key(12)
AttributeError: 'dict' object has no attribute 'has_key'
$ python2.7 -mtimeit -s'd=dict.fromkeys(range( 99))' 'd.has_key(12)'
10000000 loops, best of 3: 0.0872 usec per loop
$ python2.7 -mtimeit -s'd=dict.fromkeys(range(1999))' 'd.has_key(12)'
10000000 loops, best of 3: 0.0858 usec per loop
$ python3.5 -mtimeit -s'd=dict.fromkeys(range( 99))' '12 in d'
10000000 loops, best of 3: 0.031 usec per loop
$ python3.5 -mtimeit -s'd=dict.fromkeys(range(1999))' '12 in d'
10000000 loops, best of 3: 0.033 usec per loop
$ python3.5 -mtimeit -s'd=dict.fromkeys(range( 99))' '12 in d.keys()'
10000000 loops, best of 3: 0.115 usec per loop
$ python3.5 -mtimeit -s'd=dict.fromkeys(range(1999))' '12 in d.keys()'
10000000 loops, best of 3: 0.117 usec per loop
Se hai qualcosa del genere:
t.has_key(ew)
cambiarlo in basso per l'esecuzione su Python 3.X e versioni successive:
key = ew
if key not in t
t.has_key(ew)
ritorna True
se anche i ew
riferimenti ai valori sono una chiave nel dizionario. key not in t
ritorna True
se il valore non è nel dizionario. Inoltre, l' key = ew
alias è molto, molto ridondante. L'ortografia corretta è if ew in t
. È ciò che ti ha già detto la risposta accettata di 8 anni prima.