In Python, c'è una differenza tra chiamare clear()
e assegnare {}
a un dizionario? Se si, che cos'è? Esempio:
d = {"stuff":"things"}
d.clear() #this way
d = {} #vs this way
In Python, c'è una differenza tra chiamare clear()
e assegnare {}
a un dizionario? Se si, che cos'è? Esempio:
d = {"stuff":"things"}
d.clear() #this way
d = {} #vs this way
Risposte:
Se hai un'altra variabile che fa riferimento anche allo stesso dizionario, c'è una grande differenza:
>>> d = {"stuff": "things"}
>>> d2 = d
>>> d = {}
>>> d2
{'stuff': 'things'}
>>> d = {"stuff": "things"}
>>> d2 = d
>>> d.clear()
>>> d2
{}
Questo perché l'assegnazione d = {}
crea un nuovo dizionario vuoto e lo assegna alla d
variabile. Questo lascia d2
puntare al vecchio dizionario con gli elementi ancora presenti. Tuttavia, d.clear()
cancella lo stesso dizionario che d
e d2
sia punto.
Oltre alle differenze menzionate in altre risposte, esiste anche una differenza di velocità. d = {} è due volte più veloce:
python -m timeit -s "d = {}" "for i in xrange(500000): d.clear()"
10 loops, best of 3: 127 msec per loop
python -m timeit -s "d = {}" "for i in xrange(500000): d = {}"
10 loops, best of 3: 53.6 msec per loop
d = {}
dovrebbe essere più veloce poiché la pulizia completa può essere lasciata a Garbage Collector per dopo.
A titolo di esempio per le cose già menzionate prima:
>>> a = {1:2}
>>> id(a)
3073677212L
>>> a.clear()
>>> id(a)
3073677212L
>>> a = {}
>>> id(a)
3073675716L
.clear
modifica l'oggetto ma `= {}` crea un nuovo oggetto.
Oltre alla risposta di @odano, sembra che l'uso d.clear()
sia più veloce se desideri cancellare il dict per molte volte.
import timeit
p1 = '''
d = {}
for i in xrange(1000):
d[i] = i * i
for j in xrange(100):
d = {}
for i in xrange(1000):
d[i] = i * i
'''
p2 = '''
d = {}
for i in xrange(1000):
d[i] = i * i
for j in xrange(100):
d.clear()
for i in xrange(1000):
d[i] = i * i
'''
print timeit.timeit(p1, number=1000)
print timeit.timeit(p2, number=1000)
Il risultato è:
20.0367929935
19.6444659233
I metodi di mutazione sono sempre utili se l'oggetto originale non rientra nell'ambito:
def fun(d):
d.clear()
d["b"] = 2
d={"a": 2}
fun(d)
d # {'b': 2}
La riassegnazione del dizionario creerebbe un nuovo oggetto e non modificherebbe quello originale.
Una cosa non menzionata è problemi di scoping. Non è un ottimo esempio, ma ecco il caso in cui mi sono imbattuto nel problema:
def conf_decorator(dec):
"""Enables behavior like this:
@threaded
def f(): ...
or
@threaded(thread=KThread)
def f(): ...
(assuming threaded is wrapped with this function.)
Sends any accumulated kwargs to threaded.
"""
c_kwargs = {}
@wraps(dec)
def wrapped(f=None, **kwargs):
if f:
r = dec(f, **c_kwargs)
c_kwargs = {}
return r
else:
c_kwargs.update(kwargs) #<- UnboundLocalError: local variable 'c_kwargs' referenced before assignment
return wrapped
return wrapped
La soluzione è sostituirla c_kwargs = {}
conc_kwargs.clear()
Se qualcuno pensa a un esempio più pratico, non esitare a modificare questo post.
global c_kwargs
probabilmente funzionerebbe anche no? Anche se probabilmente global
non è la cosa migliore da usare molto.
global
farebbe in modo che la funzione si comporti diversamente: tutte le chiamate a conf_decorator condivideranno quindi la stessa variabile c_kwargs. Credo che Python 3 abbia aggiunto la nonlocal
parola chiave per risolvere questo problema e che funzionerebbe.
Inoltre, a volte l'istanza di dict potrebbe essere una sottoclasse di dict ( defaultdict
ad esempio). In tal caso, clear
è preferibile utilizzare , poiché non dobbiamo ricordare il tipo esatto di dict ed evitare anche il codice duplicato (accoppiando la linea di cancellazione con la linea di inizializzazione).
x = defaultdict(list)
x[1].append(2)
...
x.clear() # instead of the longer x = defaultdict(list)