readonly class attribute ?

Discussion in 'Python' started by bruno modulix, Mar 15, 2005.

  1. 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.

    TIA
    --
    bruno desthuilliers
    python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
    p in ''.split('@')])"
    bruno modulix, Mar 15, 2005
    #1
    1. Advertising

  2. Start the attribute name with "_" and don't document it. If clients
    mess with it, they're to blame.
    Simon Percivall, Mar 15, 2005
    #2
    1. Advertising

  3. On Tue, 15 Mar 2005 20:21:19 +0100, bruno modulix <> 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
    Bengt Richter, Mar 15, 2005
    #3
  4. 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
    Bruno Desthuilliers, Mar 15, 2005
    #4
  5. Bengt Richter a écrit :
    > On Tue, 15 Mar 2005 20:21:19 +0100, bruno modulix <> 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 !-)
    Bruno Desthuilliers, Mar 15, 2005
    #5
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Matt
    Replies:
    1
    Views:
    4,153
  2. Matt
    Replies:
    2
    Views:
    19,011
  3. Hamed
    Replies:
    3
    Views:
    658
    Eliyahu Goldin
    Jul 9, 2006
  4. Bogdan
    Replies:
    0
    Views:
    306
    Bogdan
    Apr 17, 2008
  5. Jonathan Hyatt
    Replies:
    1
    Views:
    1,865
    Jonathan Hyatt
    Jun 8, 2004
Loading...

Share This Page