On Tue, 15 Mar 2005 20:21:19 +0100, bruno modulix <[EMAIL PROTECTED]> wrote:
>Hi > >How can I make a *class* attribute read-only ? > >The answer must be pretty obvious but I just can't find it (it's late >and I've spent all day on metaclasses, descriptors and the like, which, >as fun as it is, may have side-effects on intellectual abilities...) > >*The context:* > ># library code >class AbstractBaseClass(object): > # snip some stuff here, > # a part of it depending on the derived classes > # defining class attribute class_private_attrib > ># client code >class SubClass(AbstractBaseClass): > class_private_attrib = "my private attrib" > # snip > > >*What I'm looking for: (if possible)* > > >>SubClass.class_private_attrib >"my private attrib" > >>SubClass.class_private_attrib = "toto" >AttributeError : SubClass.class_private_attrib is read only > >>s = SubClass() > >>s.class_private_attribute = "toto" >AttributeError : SubClass.class_private_attrib is read only > >*What I've tried: (simplified as possible)* > >class ReadOnlyDescriptor(object): > def __init__(self, name, initval=None): > self._val = initval > self._name = name > > def __get__(self, obj, objtype): > print 'Retrieving', self._name > return self._val > > def __set__(self, obj, val): > raise AttributeError, \ > "%s.%s is ReadOnly" % (obj.__class.__.__name__, self._name) > >class SubClass(object): > class_private_attrib = ReadOnlyDescriptor("class_private_attrib", > "my private attrib") > # snip > >*What i get:* > >>SubClass.class_private_attrib >Retrieving class_private_attrib >"my private attrib" > >>SubClass.class_private_attrib = "toto" > >>SubClass.class_private_attrib >"toto" > >>SubClass.__dict__['class_private_attrib'] >"toto" > >> s = SubClass() > >> s.class_private_attrib >"toto" # of course :( > >*What I understand:* >Ok, I've re-read the manual, noticed that data descriptors __set__() >method was only called when an instance attribute is set (which is >obvious from the prototypes of the methods). My solution is plain wrong >and I should have guess without ever trying. duh :( > > >Now please have mercy, you Noble Pythoneers : what's the trick to >prevent client code to accidentally mess with the class's dict ? (most >client code - apart from subclass definitions - shouldn't even bother >about the existence of this attribute, it's there for the library >internal usage) > >NB : in the real code I'm also messing with the AbstractBaseClass's >meta_class for other stuff (so it's not a problem if the solution >involves metaclasses), but I've tested with the simplified example >above, which exhibits the same problem. > Does this help, or did I misunderstand? >>> class Base(object): ... class __metaclass__(type): ... def __setattr__(cls, name, value): ... raise AttributeError, 'setting %r to %r not allowed' %(name, value) ... >>> class Sub(Base): ... def m(self): print 'method m called' ... x = 123 ... >>> obj = Sub() Instance attributes work normally: >>> obj.x 123 >>> obj.x = 456 >>> obj.x 456 >>> del obj.x If not shadowed, the class var is found >>> Sub.x 123 But it is read-only: >>> Sub.x = 456 Traceback (most recent call last): File "<stdin>", line 1, in ? File "<stdin>", line 4, in __setattr__ AttributeError: setting 'x' to 456 not allowed >>> Base.x = 456 Traceback (most recent call last): File "<stdin>", line 1, in ? File "<stdin>", line 4, in __setattr__ AttributeError: setting 'x' to 456 not allowed >>> Sub.anything = 'something' Traceback (most recent call last): File "<stdin>", line 1, in ? File "<stdin>", line 4, in __setattr__ AttributeError: setting 'anything' to 'something' not allowed Regards, Bengt Richter -- http://mail.python.org/mailman/listinfo/python-list