A dictionary of horrors
This post demonstrates a strange behaviour encountered while
initializing a dictionary using the dict.fromkeys
method. TLDR: be
careful while passing mutable arguments such as lists.
planets = ("Mercury", "Venus", "Earth", "Mars") sattelites = dict.fromkeys(planets, value=[]) sattelites
{'Mercury': [], 'Venus': [], 'Earth': [], 'Mars': []}
sattelites["Earth"].append("Moon")
What you expect
>>> sattelites {'Mercury': [], 'Venus': [], 'Earth': ['Moon'], 'Mars': []}
What you actually get
sattelites
{'Mercury': ['Moon'], 'Venus': ['Moon'], 'Earth': ['Moon'], 'Mars': ['Moon']}
Why?
Surely string as keys are valid and hashable, no doubt about that, but this behaviour is weird.
id(sattelites["Earth"]), id(sattelites["Mars"])
(139764445576200, 139764445576200)
Apparently the same list
instance is assigned to all the dictionary
items which gets mutated. This is also the case if you initialize as
follows.
sattelites = dict.fromkeys(planets, list()) id(sattelites["Earth"]), id(sattelites["Mars"])
(139764445511368, 139764445511368)
The id
is still the same across dictionaries!
The solution: Use dictionary comprehensions
sattelites = {planet: [] for planet in planets} sattelites
{'Mercury': [], 'Venus': [], 'Earth': [], 'Mars': []}
sattelites["Earth"].append("Moon") sattelites
{'Mercury': [], 'Venus': [], 'Earth': ['Moon'], 'Mars': []}
id(sattelites["Earth"]), id(sattelites["Mars"])
(139764445567048, 139764351351752)
Finally the id
s are different :)
You can download this notebook, or see a static view on nbviewer .
About the author
Ashwin Vishnu Mohanan, Ph.D. in Fluid mechanics