This is an example from Effective Pʏᴛʜᴏɴ, that I am clearly missing something on. I added a few print's to help convince myself, but I'm still a little unclear.
I understand that when you attempt to access an inherited private variable, it fails because in the instance dictionary of the child, the name has been mangled (last line below, attempting to access a.__value rightfully fails because the instance dict contains the mangled version _ApiClass__value).
Where I'm getting tripped up is why the inherited method get doesn't have this issue. If you print self.__dict__ in the call to get, you can see that we're still working with the same Child instance dict as we would be if we attempted to use dotted access directly from the child (which contains the mangled name only). Dotted attribute access from within this method somehow properly translates to the mangled name and retrieves the private variable.
My understanding of attribute access is that under the covers, what is essentially happening (albeit simplified) is a.__value is basically a.__dict__['__value']. This makes sense and is proved out when you attempt to directly access the inherited private variable, as it fails since only the mangled name is in the Child dict. However the inherited method get, which is operating on the same instance dict from Child, works with dotted access so it is clearly not doing a.__dict__['__value'], but rather a.__dict__['_ApiClass__value'].
What is the distinction here that causes the private attribute access from within the get method to be aware of the mangled name as opposed to similar attribute access from the child?
class ApiClass(): def __init__(self): self.__value = 5 def get(self): print(self.__dict__['_ApiClass__value']) #succeeds print(self.__dict['__value']) #fails bc name mangle return self.__value # How is this translated to '_ApiClass_value' # but a similar instance lookup fails? class Child(ApiClass): def __init__(self): super().__init__() self._value = 'hello' a = Child() print(a.__dict__) print(a.get()) # Works, but instance dict has no '__value' key? print(a.__value) # Fails because name mangled to '_ApiClass_value'.
ApiClass.get()suggests that the line doesn't work, but it is fine. I can run this code with no errors except on the very last line where you try to accessa.__value.