I recognize strange behavior in my code. I extract some testcode to demonstrate:
class A:
def __init__(self):
super().__init__()
self.mystr = 'A'
self.mydict['key'] = 'value'
class B(A):
mystr = 'B'
mydict = {}
def __init__(self, name):
print(name, 'mystr (before)', self.mystr)
print(name, 'mydict (before)', self.mydict)
super().__init__()
print(name, 'mystr (after)', self.mystr)
print(name, 'mydict (after)', self.mydict)
if __name__ == '__main__':
b1 = B('b1')
b2 = B('b2')
The output is:
b1 mystr (before) B
b1 mydict (before) {}
b1 mystr (after) A
b1 mydict (after) {'key': 'value'}
b2 mystr (before) B
b2 mydict (before) {'key': 'value'} // <- I expect this to be {}
b2 mystr (after) A
b2 mydict (after) {'key': 'value'}
The property mystr works as I expected. For the second instance b2 it is ‘B’ as it was initialized. But the property mydict is not initialized correct for the second instance and contains the key/value pair:
b2 mydict (before) {‘key’: ‘value’}
I know that there a mutable and immutable variables in Python and that the first one are hold by reference. But I can explain, why my code is not working as expected.
Can somebody give me a hint?
>Solution :
Yes, you have a single dict shared by all instance of the class. The key is that
self.mydict['key'] = 'value'
is not an assignment to the attribute mydict, so it does not create a new instance attribute. Rather, it’s a method call
self.mydict.__setitem__('key', 'value')
and the lookup self.mydict resolves to A.mydict since there is no instance attribute named mydict.
On the other hand,
self.mystr = 'A'
is an assignment to an attribute, so it always creates a new instance attribute if it does not already exist, rather than changing the value of an existing class attribute of the same name. If you want to change the value of a class attribute via an instance of the class, you have to first get a reference to the class, with something like
self.__class__.mystr = 'A' # Modifies A.mystr without creating self.mystr instead