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 ids are different :)

You can download this notebook, or see a static view on nbviewer .

Ashwin Vishnu Mohanan

About the author

Ashwin Vishnu Mohanan, Ph.D. in Fluid mechanics

Posted by on in Tech Talk. updated Tags: python.

Interactions

Below you can find the interactions that this page has had using WebMention.

Have you written a response to this post? Let me know the URL:

Do you not have a website set up with WebMention capabilities? You can: