I was doing some tests with python trying to "force", so to speak, the encapsulation in python, since in python private attributes do not exist as such:
import re
class Mixin(object):
__a = 1
def __getattribute__(self, name):
if re.match(f'_{ self.__class__.__name__ }__', name):
raise AttributeError(f"'{ self.__class__.__name__ }' object has no attribute '{ name }'")
return super().__getattribute__(name)
Mixin()._Mixin__a
It is assumed that in this way the attribute could not be accessed __a
like this: _Mixin__a
.
But it gives me the following error:
Traceback (most recent call last):
File "/home/lcteen/Documentos/Programming/Python/Practices/sss.py", line 24, in <module>
Mixin()._Mixin__a
File "/home/lcteen/Documentos/Programming/Python/Practices/sss.py", line 19, in __getattribute__
if re.match(f'_{ self.__class__.__name__ }__', name):
File "/home/lcteen/Documentos/Programming/Python/Practices/sss.py", line 19, in __getattribute__
if re.match(f'_{ self.__class__.__name__ }__', name):
File "/home/lcteen/Documentos/Programming/Python/Practices/sss.py", line 19, in __getattribute__
if re.match(f'_{ self.__class__.__name__ }__', name):
[Previous line repeated 996 more times]
RecursionError: maximum recursion depth exceeded
I do not understand what I am doing wrong, nor why the error occurs.
It is perhaps the most common error when reimplementing
__getattribute__
. The minimum code to reproduce the problem is very basic:Note that when implemented
__getattribute__
, such a method is always the entry point for any access to attributes of the instance.Let's analyze the previous example:
Mixin().test
creates an instance of the class and tries to access the attributetest
.The above causes the method to be called as
__getattribute__
follows:The line is executed
self.__class__
, causing it to be called again__getattribute__
:The line is reached again
self.__class__
.... And so on until the stack is full and the interpreter explodes, well no, because Python limits the allowed recursive calls to 1000 by default and shows us the aforementioned error.The solution in these cases is always to delegate the resolution of the attribute to the parent class (
object
in this case), thus avoiding the recursive call. The normal thing is to usesuper
for it:super ()
returns a proxy object that will look up any methods that can be found below in the base classes following the MRO. If no such method exists, it will fail with aAttributeError
but never call the original method.Alternatively, you can call the method
__getattribute__
directlyobjet
. The C implementation of the method is always the endpoint in the MRO for attribute access and has direct access to__dict__
.