2008-12-15 19 views

Respuesta

238

Si usted tiene otra variable también se refieren al mismo diccionario, hay una gran diferencia:

>>> d = {"stuff": "things"} 
>>> d2 = d 
>>> d = {} 
>>> d2 
{'stuff': 'things'} 
>>> d = {"stuff": "things"} 
>>> d2 = d 
>>> d.clear() 
>>> d2 
{} 

Esto se debe a la asignación de d = {} crea un nuevo diccionario, vacío y lo asigna a la d variable. Esto deja d2 apuntando al viejo diccionario con los elementos que todavía están en él. Sin embargo, d.clear() borra el mismo diccionario que d y d2 ambos apuntan a.

+5

Gracias. Esto tiene sentido. Todavía tengo que acostumbrarme a la mentalidad de que = crea referencias en python ... – Marcin

+8

= copia referencias a nombres. No hay variables en python, solo objetos y nombres. – tzot

+15

Si bien su declaración de "no variables" es pedantemente verdadera, no es realmente útil aquí. Mientras la documentación del lenguaje Python todavía hable de "variables", todavía voy a utilizar el término: http://docs.python.org/reference/datamodel.html –

26

d = {} creará una nueva instancia para d pero todas las demás referencias seguirán señalando los contenidos anteriores. d.clear() restablecerá el contenido, pero todas las referencias a la misma instancia seguirán siendo correctas.

18

Además de las diferencias mencionadas en otras respuestas, también hay una diferencia de velocidad. d = {} es más de dos veces más rápido:

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 
+7

Esto no es realmente una prueba de velocidad válida para todos los casos dado que el dict está vacío. Creo que crear un dict grande (o al menos un poco de contenido) produciría una diferencia de rendimiento mucho menor ... además, sospecho que el recolector de basura podría agregar un poco de daño a d = {} (?) – Rafe

+0

@Rafe: I piense que el punto es que si sabemos que ninguna otra variable apunta al diccionario d, entonces establecer 'd = {}' debería ser más rápido ya que la limpieza completa se puede dejar en Garbage Collector para más adelante. – ViFI

5

A modo de ejemplo de las cosas ya mencionadas antes:

>>> a = {1:2} 
>>> id(a) 
3073677212L 
>>> a.clear() 
>>> id(a) 
3073677212L 
>>> a = {} 
>>> id(a) 
3073675716L 
+0

Esto muestra que '.clear' modifica el objeto pero' = {} 'crea un nuevo objeto. – wizzwizz4

7

Además de @odano 's respuesta, parece que el uso de d.clear() más rápido si se le gustaría borrar el dict por muchas veces.

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) 

El resultado es:

20.0367929935 
19.6444659233 
+3

No estoy seguro de que la diferencia sea significativa. De todos modos, en mi máquina, ¡los resultados son opuestos! – Aristide

4

Una cosa que no se menciona es cuestiones de alcance. No es un gran ejemplo, pero aquí está el caso en el que me encontré con el 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 solución es reemplazar c_kwargs = {} con c_kwargs.clear()

Si alguien piensa que un ejemplo más práctico, no dude en editar este post .

+0

'global c_kwargs' probablemente también funcionaría no? Aunque probablemente 'global' no sea lo mejor para usar mucho. – fantabolous

+3

@fantabolous usando 'global' haría que la función se comportara de manera diferente: todas las llamadas a conf_decorator compartirían la misma variable c_kwargs. Creo que Python 3 agregó la palabra clave 'nonlocal' para abordar este problema, y ​​eso funcionaría. – Ponkadoodle

5

La mutación métodos son útiles siempre si el objeto original no está en su alcance:

def fun(d): 
    d.clear() 
    d["b"] = 2 

d={"a": 2} 
fun(d) 
d   # {'b': 2} 

Reasignar el diccionario crearía un nuevo objeto y no modificaría la original.

0

Además, a veces la instancia dict podría ser una subclase de dict (defaultdict por ejemplo). En ese caso, se prefiere usar clear, ya que no tenemos que recordar el tipo exacto del dict, y también evitar el código duplicado (acoplar la línea de compensación con la línea de inicialización).

x = defaultdict(list) 
x[1].append(2) 
... 
x.clear() # instead of the longer x = defaultdict(list) 
Cuestiones relacionadas