Home » Python » Difference between dict.clear() and assigning {} in Python

Difference between dict.clear() and assigning {} in Python

Posted by: admin November 1, 2017 Leave a comment

Questions:

In python, is there a difference between calling clear() and assigning {} to a dictionary? If yes, what is it?
Example:

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

Answers:

If you have another variable also referring to the same dictionary, there is a big difference:

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

This is because assigning d = {} creates a new, empty dictionary and assigns it to the d variable. This leaves d2 pointing at the old dictionary with items still in it. However, d.clear() clears the same dictionary that d and d2 both point at.

Questions:
Answers:

d = {} will create a new instance for d but all other references will still point to the old contents.
d.clear() will reset the contents, but all references to the same instance will still be correct.

Questions:
Answers:

In addition to the differences mentioned in other answers, there also is a speed difference. d = {} is over twice as fast:

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

Questions:
Answers:

In addition to @odano ‘s answer, it seems using d.clear() is faster if you would like to clear the dict for many times.

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)

The result is:

20.0367929935
19.6444659233

Questions:
Answers:

As an illustration for the things already mentioned before:

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

Questions:
Answers:

Mutating methods are always useful if the original object is not in scope:

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

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

Re-assigning the dictionary would create a new object and wouldn’t modify the original one.

Questions:
Answers:

One thing not mentioned is scoping issues. Not a great example, but here’s the case where I ran into the problem:

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

The solution is to replace c_kwargs = {} with c_kwargs.clear()

If someone thinks up a more practical example, feel free to edit this post.

Questions:
Answers:

In addition, sometimes the dict instance might be a subclass of dict (defaultdict for example). In that case, using clear is preferred, as we don’t have to remember the exact type of the dict, and also avoid duplicate code (coupling the clearing line with the initialization line).

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