3

I create two identical dictionaries containing lists using two different methods:

dictA = dict.fromkeys(["key1", "key2"], [])
dictB = {
    "key1": [],
    "key2": [],
}

Yet, when I append a random value or list to a specific key of each dictionary:

dictA["key2"].append(1)
dictB["key2"].append(1)

...I end up with different results:

{'key1': [1], 'key2': [1]}
{'key1': [], 'key2': [1]}

Why is that?

MichlF
  • 139
  • 1
  • 8

1 Answers1

2

That's because the default value of dict.fromkeys(), when mutable, points to a single object. You can do the test like this:

d = {}.fromkeys(['a', 'b'], [])

print(id(d['a']))
print(id(d['b']))
Out[115]: 2315628170504
Out[116]: 2315628170504

The value of the keys 'a' and 'b' points to the same object.

Nicolas Gervais
  • 33,817
  • 13
  • 115
  • 143
  • Is this expected behavior? Is there really a used case for this? – MichlF Jul 05 '20 at 02:15
  • 1
    it is expected. the reason is quite complicated, here's some [introductory reading](https://stackoverflow.com/questions/1132941/least-astonishment-and-the-mutable-default-argument). – Nicolas Gervais Jul 05 '20 at 02:17
  • @MichelF. This is pretty consistent across python. Get used to it. Multiple variables/keys/etc can and will refer to the exact same object. – user1558604 Jul 05 '20 at 02:18
  • @MichelF. That is the expected behavior. The doc string says _...and values set to value._. It makes sense when you want, say, integer 0 or a default string. You are using a mutable container, but the thing is, how to copy objects to make the values unique is ambiguous. A list, okay, ... but then should that deep copy all contained objects? And what about a generic class `Foo`. What then? Since there isn't a good general choice for copying, the good choice is not to implement it in a foundation object such as list. – tdelaney Jul 05 '20 at 02:19