pythonlistdictionary

Dictionary creation with fromkeys and mutable objects. A surprise


I came across this behavior that surprised me in Python 2.6 and 3.2:

>>> xs = dict.fromkeys(range(2), [])
>>> xs
{0: [], 1: []}
>>> xs[0].append(1)
>>> xs
{0: [1], 1: [1]}

However, dict comprehensions in 3.2 show a more polite demeanor:

>>> xs = {i:[] for i in range(2)}
>>> xs
{0: [], 1: []}
>>> xs[0].append(1)
>>> xs
{0: [1], 1: []}
>>> 

Why does fromkeys behave like that?


Solution

  • Your Python 2.6 example is equivalent to the following, which may help to clarify:

    >>> a = []
    >>> xs = dict.fromkeys(range(2), a)
    

    Each entry in the resulting dictionary will have a reference to the same object. The effects of mutating that object will be visible through every dict entry, as you've seen, because it's one object.

    >>> xs[0] is a and xs[1] is a
    True
    

    Use a dict comprehension, or if you're stuck on Python 2.6 or older and you don't have dictionary comprehensions, you can get the dict comprehension behavior by using dict() with a generator expression:

    xs = dict((i, []) for i in range(2))