11

I have a dictionary of empty lists with all keys declared at the beginning:

>>> keys = ["k1", "k2", "k3"]
>>> d = dict.fromkeys(keys, [])
>>> d
{'k2': [], 'k3': [], 'k1': []}

When I try to add a coordinate pair (the list ["x1", "y1"]) to one of the key's lists, it instead adds to all the keys' lists:

>>> d["k1"].append(["x1", "y1"])
>>> d
{'k1': [['x1', 'y1']], 'k2': [['x1', 'y1']], 'k3': [['x1', 'y1']]}

What I was looking for was:

>>> d
{'k1': [['x1', 'y1']], 'k3': [], 'k1': []}

How can I achieve this in Python 3?

Mike Müller
  • 82,630
  • 20
  • 166
  • 161
user1717828
  • 7,122
  • 8
  • 34
  • 59

3 Answers3

12

Looks like each of those lists is actually a reference to a single list. Appending to one of them appends to all of them.

I don't think you can work around this while still using fromkeys. Try using a dict comprehension instead.

d = {k: [] for k in keys}
Kevin
  • 74,910
  • 12
  • 133
  • 166
4

Create your dictionary like this:

d = {k: [] for k in keys}

dict.fromkeys() puts a reference to the same list as value for all keys into the dictionary.

You can visualize this by looking at the id of your values:

>>> d = dict.fromkeys(keys,[])
>>> [id(v) for v in d.values()]
[4413495432, 4413495432, 4413495432]

Because the id uniquely identifies an object, this means you have the same object three times.

Mike Müller
  • 82,630
  • 20
  • 166
  • 161
4

The fromkeys is a class method which passes the second argument as the value for all of the keys, thus they all would reference to one object. instead you if you don't pass the value python will consider the None as the value for each item. Then instead of append you can assign a 2d list to your key:

>>> d = dict.fromkeys(keys)
>>> d["k1"] = [["x1", "y1"]]
>>> d
{'k3': None, 'k2': None, 'k1': [['x1', 'y1']]}

This is how python has created the fromkeys method:

@classmethod
def fromkeys(cls, iterable, value=None):
    d = cls()
    for key in iterable:
        d[key] = value
    return d
styvane
  • 59,869
  • 19
  • 150
  • 156
Mazdak
  • 105,000
  • 18
  • 159
  • 188