I made a simple repro of my issue below. I have a class with an instance variable (inst_dict) which is of type dict. I also have a class variable (myClass_dict) which I use to keep track of each instance of my class.
What I am trying to do is update one value of inst_dict with a certain value. My problem is that it is updating the value for every instance.
Below is the code that almost does what I am aiming to do. The line inst.inst_dict = {"key1": i, "key2": "Val2"}
sets the whole dict to the new value based on i. I am trying to just set one value in the dict, rather than the whole dict. The line after that is commented out is what I expected to work, where I access inst_dict for the current instance, then set the value of "key" to i.
When I run it with that line it updates the value of "key" in the dict, but for every instance. It's like it gets changed to a class variable somewhere.
class My_Class(object):
myClass_dict = {}
def __init__(self, name, inst_dict = {}):
My_Class.myClass_dict[name] = self
self.name = name
self.inst_dict = inst_dict
for i in range(5):
name = f'inst{i}'
inst = My_Class(name)
inst.inst_dict = {"key1": i, "key2": "Val2"} #This works but changes the whole dict
# inst.inst_dict['key'] = i #This changes one value, but updates every instance
print(name)
for inst in My_Class.myClass_dict:
print(f' {My_Class.myClass_dict[inst].name} {My_Class.myClass_dict[inst].inst_dict}')
Can somebody explain why this is updating every instance, and how I can avoid that?
Thanks!
edit: Here is the output when running this with the first line (as written above):
inst0
inst0 {'key1': 0, 'key2': 'Val2'}
inst1
inst0 {'key1': 0, 'key2': 'Val2'}
inst1 {'key1': 1, 'key2': 'Val2'}
inst2
inst0 {'key1': 0, 'key2': 'Val2'}
inst1 {'key1': 1, 'key2': 'Val2'}
inst2 {'key1': 2, 'key2': 'Val2'}
inst3
inst0 {'key1': 0, 'key2': 'Val2'}
inst1 {'key1': 1, 'key2': 'Val2'}
inst2 {'key1': 2, 'key2': 'Val2'}
inst3 {'key1': 3, 'key2': 'Val2'}
inst4
inst0 {'key1': 0, 'key2': 'Val2'}
inst1 {'key1': 1, 'key2': 'Val2'}
inst2 {'key1': 2, 'key2': 'Val2'}
inst3 {'key1': 3, 'key2': 'Val2'}
inst4 {'key1': 4, 'key2': 'Val2'}
As you can see, at each loop it updates the corresponding instance key1 to the value of i (0,1,2,3,4). And the value of key1 for inst0 remains unchanged in the following loops.
And here is when I comment that line, and uncomment the next line:
inst0
inst0 {'key': 0}
inst1
inst0 {'key': 1}
inst1 {'key': 1}
inst2
inst0 {'key': 2}
inst1 {'key': 2}
inst2 {'key': 2}
inst3
inst0 {'key': 3}
inst1 {'key': 3}
inst2 {'key': 3}
inst3 {'key': 3}
inst4
inst0 {'key': 4}
inst1 {'key': 4}
inst2 {'key': 4}
inst3 {'key': 4}
inst4 {'key': 4}
As you can see, at each loop, it updates every instance that has been created. On the fourth loop, it not only updates inst4, but also inst 0 through 3.
CodePudding user response:
Long story short: dict in python is mutable and therefore not advisible to be used as default value. See this post for example: Why is the empty dictionary a dangerous default value in Python?
The empty dict is constructed only once when defining the class and then every instance uses it - and updates it. EXCEPT for when you assign a whole new value: That works. If you want to have a "fresh" empty dict for every instance, the common construction is:
class My_Class(object):
myClass_dict = {}
def __init__(self, name, inst_dict = None):
My_Class.myClass_dict[name] = self
self.name = name
if inst_dict is not None:
self.inst_dict = inst_dict
else:
self.inst_dict = {}