python 3, new to coding and python. i built a class dictionary with default values, then attempted to build a nested dictionary based on that class dictionary and encountered unexpected behaviour:
class User:
def __init__(self, *, name=None, age=None, hobbies=[]):
self.name = name
self.age = age
self.hobbies = hobbies
counter = 0
class_dict = {}
# building the nested dicts with default values
for num in range(0, 3):
"""
1. referencing "User.__init__.__kwdefaults__"
vs writting the actual dict directly into the nested dict
2. {"name": None, "age": None, "hobbies": []}
"""
class_dict.update({f"key_{num}": User.__init__.__kwdefaults__})
# class_dict.update({f"key_{num}": {"name": None, "age": None, "hobbies": []}})
print("Blue print: " + str(class_dict))
# updating values in the nested dicts
for x in range(0, 3): # simplified loop
dict_key = "key_" + str(counter)
try:
if 1 < 2: # simplified if check
class_dict[dict_key]["name"] = "updated" + str(counter)
print("inside loop: " + str(class_dict))
counter = counter + 1
except:
continue
print("<<< final result: " + str(class_dict) + ">>>") # end-result
the " User.init.kwdefaults " version will updated the correct nested dicts keys inside the loop as expected, but as end result all 3 nested dicts "name" key store "updated2" as value. what ever gets changed in the last iteration of the loop gets changed in all the nested dicts.
the actual dict " {"name": None, "age": None, "hobbies": []} " version also updates the correct nested dict keys inside the loop as expected. however the end result here for the "name" key in nested dict 1 stores the value "updated0", in nested dict 2 "updated1" and in nested 2 "updated2".
the end result of 2. is what i was aiming for and it took me a while to find the issue. i don't understand why both versions behave identically inside the loop but net different end results. is there a dunder/magic method to reference the class dictionary and get version 2. as end result?
The problem is that you are assigning the same subdict over and over again to every key as you could check by running this after your code:
for x in range(0, 2): # simplified loop
dict_key = "key_" + str(x)
dict_key2 = "key_" + str(x+1)
print(f'subdict of key {x} is subdict of key {x+1}: {class_dict[dict_key] is class_dict[dict_key2]}')
The output is:
subdict of key 0 is subdict of key 1: True
subdict of key 1 is subdict of key 2: True
A solution would be by using deep copies as:
import copy
class User:
def __init__(self, *, name=None, age=None, hobbies=[]):
self.name = name
self.age = age
self.hobbies = hobbies
counter = 0
class_dict = {}
# building the nested dicts with default values
for num in range(0, 3):
"""
1. referencing "User.__init__.__kwdefaults__"
vs writting the actual dict directly into the nested dict
2. {"name": None, "age": None, "hobbies": []}
"""
class_dict.update({f"key_{num}": copy.deepcopy(User.__init__.__kwdefaults__)})
# class_dict.update({f"key_{num}": {"name": None, "age": None, "hobbies": []}})
print("Blue print: " + str(class_dict))