readonly class attribute ?

Bengt Richter bokr at oz.net
Tue Mar 15 15:45:49 EST 2005


On Tue, 15 Mar 2005 20:21:19 +0100, bruno modulix <onurb at xiludom.gro> 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



More information about the Python-list mailing list