0

Here's the question - When a class has a dictionary, that is initialized in the init method, the manner in which it is initialized can lead the dictionary to be shared between all instances.

Here is a test code that shows different ways to initialize a dictionary:

class testDic:
        def __init__(self,name,aDic={},**kwargs):
                self.name=name
                self.aDic=aDic
                self.anotherDic={}
                self.kwDic=kwargs.get('dic',{})

        def print(self):
                print(self.name,' aDic : ',self.aDic,' anotherDic: ',self.anotherDic," kwDic : ",self.kwDic)

print("dics initialised: ")
obj1=testDic('obj1',aDic={'key1':1})
obj2=testDic('obj2',aDic={'key2':2})
obj1.print()
obj2.print()
print("aDic address ",obj1.name,id(obj1.aDic))
print("aDic address ",obj2.name,id(obj2.aDic))

print("dics updated: ")
obj3=testDic('obj3')
obj4=testDic('obj4')
obj3.aDic.update({'key3':3})
obj4.aDic.update({'key4':4})
obj3.anotherDic.update({'anotherKey3':3})
obj4.anotherDic.update({'anotherKey4':4})
obj3.kwDic.update({'kwKey3':3})
obj4.kwDic.update({'kwKey4':4})

obj3.print()
obj4.print()
print("aDic address ",obj3.name,id(obj3.aDic))
print("aDic address ",obj4.name,id(obj4.aDic))
print("anotherDic address ",obj3.name,id(obj3.anotherDic))
print("anotherDic address ",obj4.name,id(obj4.anotherDic))
print("kwDic address ",obj3.name,id(obj3.kwDic))
print("kwDic address ",obj4.name,id(obj4.kwDic))

The outcome of this code is as follows:

dics initialised: 
obj1  aDic :  {'key1': 1}  anotherDic:  {}  kwDic :  {}
obj2  aDic :  {'key2': 2}  anotherDic:  {}  kwDic :  {}
aDic address  obj1 140281810029952
aDic address  obj2 140281809223296
dics updated: 
obj3  aDic :  {'key3': 3, 'key4': 4}  anotherDic:  {'anotherKey3': 3}  kwDic :  {'kwKey3': 3}
obj4  aDic :  {'key3': 3, 'key4': 4}  anotherDic:  {'anotherKey4': 4}  kwDic :  {'kwKey4': 4}
aDic address  obj3 140281810030016
aDic address  obj4 140281810030016
anotherDic address  obj3 140281809318208
anotherDic address  obj4 140281809318720
kwDic address  obj3 140281809318464
kwDic address  obj4 140281809318592

As the output of the code shows, there's an issue with aDic, that is initialized this way:

__init__(self, aDic={}):
    self.aDic=aDic
  1. if an existing dictionary is passed, all is fine (see output for obj1,obj2)
  2. if however no existing dictionary is passed, the same dictionary is shared between all instances, as shows:
  • aDic address obj3 140281810030016
  • aDic address obj4 140281810030016

and

  • obj3 aDic : {'key3': 3, 'key4': 4}
  • obj4 aDic : {'key3': 3, 'key4': 4}

There is no issue with anotherDic or kwDic.

What's happening here?? Thanks for your help!

PalomaLVP
  • 21
  • 5

1 Answers1

0

You should not use default mutable values. Instead, use one of the following methods (the first one is recommended):

class Foo:
    def __init__(self, a_dict=None):
        self._a_dict = a_dict or {}
class Foo:
    def __init__(self, a_dict=frozendict()):
        self._a_dict = dict(a_dict)

Note: You should use frozendict library or MappingProxyType for frozendict (visit here for more information).

Alireza Roshanzamir
  • 1,165
  • 6
  • 17