By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
443,818 Members | 1,313 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 443,818 IT Pros & Developers. It's quick & easy.

readonly class attribute ?

P: n/a
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 onlys = 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.

TIA
--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
Jul 18 '05 #1
Share this Question
Share on Google+
4 Replies


P: n/a
Start the attribute name with "_" and don't document it. If clients
mess with it, they're to blame.

Jul 18 '05 #2

P: n/a
On Tue, 15 Mar 2005 20:21:19 +0100, bruno modulix <on***@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 onlys = 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_attribRetrieving 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
Jul 18 '05 #3

P: n/a
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
Jul 18 '05 #4

P: n/a
Bengt Richter a écrit :
On Tue, 15 Mar 2005 20:21:19 +0100, bruno modulix <on***@xiludom.gro> wrote:

Hi

How can I make a *class* attribute read-only ?
(snip)

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)


Pretty obvious, indeed !

Bengt, if we meet one day, remind me to pay you a couple of your
favorite drink !-)
Jul 18 '05 #5

This discussion thread is closed

Replies have been disabled for this discussion.