I have a dataclass, it carries an INITIALIZED
state, and I only want to have users to access it if it’s in INITIALIZED state. The way that’s implemented at the moment is:
@dataclass
class MyControlledDataclass:
_INITIALIZED: bool = False
RANDOM_ATTR: str = "random"
def __getattribute__(self, key):
print("Im getting an attribute") # Line 7
if not self._INITIALIZED:
raise Exception("This class was not initialized")
try:
return getattr(self, key)
except KeyError:
print("Couldn't find Key!")
raise AttributeError(key)
def __getitem__(self, key):
print("Im getting an item")
is_initialized = getattr(self, "_INITIALIZED")
if not is_initialized:
raise Exception("initialized")
try:
return getattr(self, key)
except KeyError:
print("Couldn't find Key!")
raise AttributeError(key)
And then I actually Initialize the object like:
controlled_class = MyControlledDataclass()
# After going through the initializer I set `_INITITLIZED=True`
initializer(controlled_class)
And now, if I want to get an item, like controlled_class.RANDOM_ATTR
I would expect this to go through the __getattribute__
method, so it can first check whether this was actually initialized or not.
No if I set the breakpoint at line 7 (the print on __getattribute__
), before I move to line 8, the console already shows the recursion, and “im getting an attribute” has already printed multiple times (recursion limit). So I’m lost on what exactly is happening. Shouldn’t I be able to control the access through the __getattribute__
? It seems to run even before I move to the next line. The same thing happens with __getitem__
.
# With _INITILIZED = True
# This should work normally
"random" == controlled_class.RANDOM_ATTR
# With _INITILIZED = False
# This should raise a custom Exception saying the class was not Initialized
controlled_class.RANDOM_ATTR
# With _INITILIZED = True
# This should raise an AttributeError (it is initialized, but the key doesn't exist)
controlled_class.DONT_EXIST
I could use @property
all around, but I have over 100 items, so not really optimal.
Ideas on what I might be doing wrong? Or workarounds?
I’m on Python 3.10.6