Problems with changing value in nested dictionaries

Hi! I’ve faced with a problem while making U.S. Medical Insurance Cost project.

First I create a dictionary using keys of another dictionary:

age_groups = {'A': (0, 18), 'B': (19, 35), 'C': (36, 50), 'D': (51, 70), 'E': (71, 95), 'F': (96, 120)}
counter = dict.fromkeys(age_groups, {'total': 0, 'male': 0, 'female': 0})

I need it as a skeleton for further records. As a result I get a nested dictionary, just like I wanted:

{'A': {'total': 0, 'male': 0, 'female': 0}, 'B': {'total': 0, 'male': 0, 'female': 0}, 'C': {'total': 0, 'male': 0, 'female': 0}, 'D': {'total': 0, 'male': 0, 'female': 0}, 'E': {'total': 0, 'male': 0, 'female': 0}, 'F': {'total': 0, 'male': 0, 'female': 0}}

Then I try to change the value of the key 'total' of the dictionary which is the value of the key 'B', like we usually do in 2D dictionaries:

counter['B']['total'] = 2

But instead of changing the 'total' value only in 'B' it changes 'total's in all keys:

{'A': {'total': 2, 'male': 0, 'female': 0}, 'B': {'total': 2, 'male': 0, 'female': 0}, 'C': {'total': 2, 'male': 0, 'female': 0}, 'D': {'total': 2, 'male': 0, 'female': 0}, 'E': {'total': 2, 'male': 0, 'female': 0}, 'F': {'total': 2, 'male': 0, 'female': 0}}

I’ve been trying different ways and I’ve found that it works correctly if I set counter dictionary directly via simple typing. So, what’s wrong with dictionaries created by dict.fromkeys() method or what did I do wrong?

Unfortunately the value you’d passed to the .fromkeys value parameter isn’t recreated for each new key, it uses the same value. Since that value is a mutable object when you make a change that change is reflected wherever that object is referenced (and each key in the new dictionary references the same object).

Since you need a new object for each key (or at least a copy) I think some form of looping/iteration would be the best option for this. There may be a few ways to do it but I’m quite partial to the dictionary comprehension-

counter = {
    group: {"total": 0, "male": 0, "female": 0}
    for group in age_groups