web-dev-qa-db-fra.com

Différence entre dict.clear () et assigning {} dans Python

En python, existe-t-il une différence entre appeler clear() et attribuer {} à un dictionnaire? Si oui, qu'est ce que c'est? Exemple:

d = {"stuff":"things"}
d.clear()   #this way
d = {}      #vs this way
155
Marcin

Si vous avez une autre variable faisant également référence au même dictionnaire, il y a une grande différence:

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

En effet, l’affectation de d = {} Crée un nouveau dictionnaire vide et l’assigne à la variable d. Cela laisse d2 Pointer vers l'ancien dictionnaire avec des éléments encore dans celui-ci. Cependant, d.clear() efface le même dictionnaire que celui que d et d2 Désignent tous les deux.

266
Greg Hewgill

d = {} Créera une nouvelle instance pour d mais toutes les autres références pointeront toujours sur l'ancien contenu. d.clear() réinitialisera le contenu, mais toutes les références à la même instance seront toujours correctes.

29
Michel

Outre les différences mentionnées dans d'autres réponses, il existe également une différence de vitesse. d = {} est deux fois plus rapide:

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
21
odano

En plus de la réponse de @odano, il semble que l'utilisation de d.clear() soit plus rapide si vous souhaitez effacer le dict plusieurs fois.

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)

Le résultat est:

20.0367929935
19.6444659233
7
lastland

Les méthodes Mutating sont toujours utiles si l'objet d'origine n'est pas dans la portée:

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

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

Réaffecter le dictionnaire créerait un nouvel objet et ne modifierait pas celui d'origine.

7
Karoly Horvath

Pour illustrer les choses déjà mentionnées auparavant:

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

Une chose non mentionnée concerne les problèmes de portée. Pas un bon exemple, mais voici le cas où j'ai rencontré le problème:

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 solution consiste à remplacer c_kwargs = {} Par c_kwargs.clear()

Si quelqu'un pense à un exemple plus pratique, n'hésitez pas à éditer ce post.

4
Ponkadoodle

De plus, l'instance dict peut parfois être une sous-classe de dict (defaultdict par exemple). Dans ce cas, il est préférable d’utiliser clear, car nous n’avons pas à nous rappeler le type exact du dict ni à éviter le code en double (couplage de la ligne de compensation avec la ligne d’initialisation).

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