This is entirely by design.
Methods on classes are attributes on the class too (albeit enhanced by being descriptors as well). This is how self.methodA()
would be located too.
Python searches attributes first on the instance, then the class, then the base classes of the class.
Note that setting self.A
will still set the value on the instance, thereby masking the class attribute. This lets classes specify default values for attributes, to be replaced by values on the instance later on.
This all doesn't preclude you from accessing ClassA.A
directly and bypass the instance dictionary. If you wanted to change the shared value, you'd have to assign directly to ClassA.A
for the above reason.