readonly class attribute ?

B

bruno modulix

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)*
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:*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.

TIA
 
S

Simon Percivall

Start the attribute name with "_" and don't document it. If clients
mess with it, they're to blame.
 
B

Bengt Richter

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)*
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:*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 __metaclass__(type):
... def __setattr__(cls, name, value):
... raise AttributeError, 'setting %r to %r not allowed' %(name, value)
... ... def m(self): print 'method m called'
... x = 123
...
Instance attributes work normally:
If not shadowed, the class var is found 123

But it is read-only: Traceback (most recent call last):
File "<stdin>", line 1, in ?
Traceback (most recent call last):
File "<stdin>", line 1, in ?
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
 
B

Bruno Desthuilliers

Simon Percivall a écrit :
Start the attribute name with "_" and don't document it. If clients
mess with it, they're to blame.

The problem is that client code must *define* this attribute when
subclassing BaseClass - and that's (well, in most case that should be)
the only place where they have to deal with it (unless they want to do
mumbo-jumbo thangs, in which case that's not my problem anymore !-).

What I want is to prevent client code to accidentally mess with it, and
have strange bugs that they may have hard time to fix. At the same time,
I want to have the cleanest syntax for the subclass declaration. In
fact, in most cases, the client code should not have much more to do
than defining a handfull of class attributes to end up with a
taylor-made fully functional subclass.

Bruno
 
B

Bruno Desthuilliers

Bengt Richter a écrit :
(snip)

Does this help, or did I misunderstand?

... class __metaclass__(type):
... def __setattr__(cls, name, value):
... raise AttributeError, 'setting %r to %r not allowed' %(name, value)

Pretty obvious, indeed !

Bengt, if we meet one day, remind me to pay you a couple of your
favorite drink !-)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top