I'm trying to set attributes to a class of which I don't know the name a-priori. I also want to avoid users to write to that attribute, so I use a property factory with getters and setters which returns a property object. However, when calling the property object, I get the reference to that object, instead of whatever the getter should be returning.
So I try to do this:
def property_factory(name):
def getter(self):
return self.__getattribute__(name)
def setter(self, value):
raise Exception('Cannot set a value')
return property(getter, setter)
# This is just a read_file placeholder
class read_file(object):
def __init__(self):
self.name = 'myName'
self.value = 'myValue'
def __iter__(self):
return self
class a(object):
list1 = read_file()
def __init__(self):
list1 = read_file()
self.__setattr__('_' + list1.name, list1.value)
# this doesn't work:
self.__setattr__(list1.name, property_factory('_' + list1.name))
# this actually does work, but with the wrong attribute name:
notMyName = property_factory('_' + list1.name)
Then I get this:
In [38]: b = a()
In [39]: b.myName
Out[39]: <property at 0x2883d454450>
In [40]: b.notMyName
Out[40]: 'myValue'
In [41]: b.notMyName = 'true'
---------------------------------------------------------------------------
Exception Traceback (most recent call last)
Cell In[41], line 1
----> 1 b.notMyName = 'true'
Cell In[37], line 6, in property_factory.<locals>.setter(self, value)
5 def setter(self, value):
----> 6 raise Exception('Cannot set a value')
Exception: Cannot set a value
What I want is this:
In [39]: b.myName
Out[40]: 'myValue'
In [41]: b.MyName = 'true'
---------------------------------------------------------------------------
Exception Traceback (most recent call last)
Cell In[41], line 1
----> 1 b.MyName = 'true'
Cell In[37], line 6, in property_factory.<locals>.setter(self, value)
5 def setter(self, value):
----> 6 raise Exception('Cannot set a value')
Exception: Cannot set a value
How do I do this?
Why do you want to do this? I've always gone back to this answer whenever I have an idea that uses the notion of dynamically-named attributes -- which is essentially what you're trying to do here if I'm not mistaken (with added read-only "protection" applied only to the keys in list1
). Do you need to use a property factory? You could do something like this:
class A(object):
list1 = read_file()
def __init__(self):
self.__dict__[A.list1.name] = A.list1.value
def __setattr__(self, name, value):
if name == A.list1.name:
raise Exception('Cannot set a value for this key!')
Now at least this works:
>>> b = A()
>>> b.myName
'myValue'
>>> b.myName = 'true'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in __setattr__
Exception: Cannot set a value for this key!
However both methods will be susecptable to the following:
>>> b.__dict__['myName'] = 'true'
>>> b.myName
'true'
Obviously there's a lot of optimization to be done here, adding sentinels, name mangling, etc, plus I'd need a lot more information regarding ultimately what you're trying to achieve and why -- but is this getting a little closer to what you want? I'll delete this answer (or tidy) if necessary, too long for a comment. Also, typo:
In [41]: b.MyName = 'true'
Should be myName
.