3

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?

asked May 26, 2023 at 15:45
2
  • 1
    property must be attached to a class object, not to an instance. Try: setattr(self.__class__, list1.name, property_factory('_' + list1.name)). However, in this way all instances of a will have the same named properties. Commented May 26, 2023 at 17:38
  • This actually also works indeed. Apply property to a class, need to remember that :). Thanks! Commented May 27, 2023 at 14:41

1 Answer 1

1

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.

answered May 26, 2023 at 19:52
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks! The property factory was not a goal on its own, just my way of implementing write protection for stuff in list1. Your method is much cleaner, I like it.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.