I'm trying to build a system where a base class is used for every other object. Every base object has a _fields
dictionary internally where implementations of the base class can store their information.
Base class implementation is quite simple:
class A(object):
def __init__(self, fields=dict()):
self._fields = fields
An implementation of the class can set the field in the __init__
call to its super()
.
What I'd like to add is that the fields are accessible as properties without having to add the @property
decorator to a whole bunch of functions. I've overriden the __getattr__
for this purpose in the base class like so:
class A(object):
def __init__(self, fields=dict()):
self._fields = fields
def __getattr__(self, name):
if hasattr(self, name):
return object.__getattribute__(self, name)
elif name in self._fields:
return self._fields.get(name)
else:
raise AttributeError
Now an implementation for this class can work like this:
class A_impl(A):
def __init__(self):
super(A_impl, self).__init__(
fields=dict(
val_1="foo",
val_2="",
val_3="bar",
)
)
By which creating an implementation of this class gives you the options to do:
test = A_imp()
print test.val_1
print test.val_2
print test.val_3
Which returns
foo
bar
I can even override this via @property
decorators, changing the class like so:
class A_impl(A):
def __init__(self):
super(A_impl, self).__init__(
fields=dict(
val_1="foo",
val_2="",
val_3="bar",
)
)
@property
def val_1(self):
return self._fields.get('val_1') + "_getter"
Which allows me to manipulate the data for return. The only issue is that if I want to be able to set one of these field variables I have to implement the descriptor setter functions which also requires me to make the property descriptor which creates a lot of duplicate work (ie I have to define descriptors for ALL my fields which is what I want to avoid here.
I implemented the __setattr__
function for the base class to solve the issue where if I manually implement a descriptor setter function it should be chosen over the default which is self._field[name] = value
. The base class now looks like this (similar to the __getattr__
):
class A(object):
def __init__(self, fields=dict()):
self._fields = fields
def __getattr__(self, name):
if hasattr(self, name):
return object.__getattribute__(self, name)
elif name in self._fields:
return self._fields.get(name)
else:
raise AttributeError
def __setattr__(self, name, value):
if hasattr(self, name):
object.__setattr__(self, name, value)
elif name in self._fields:
self._fields[name] = value
else:
raise AttributeError
Now if I run the same code test again:
test = A_imp()
print test.val_1
print test.val_2
print test.val_3
It instantly gets stuck in an infinite loop, it starts at the __setattr__
but jumps into the __getattr__
right after and keeps looping that.
I've been reading a lot of questions on stackoverflow for this and couldn't figure it out, this is why I build this test case to cleanly figure it out. Hopefully someone's able to clarify this for me and help me solve the issue.