10

Possible Duplicate:
Private functions / Variables enforcement in python

Can one create an equivalent to the following class with two static properties, one read-only and the other read-write in Python?

class Foo
{
    private static string _rdy = "RO";
    public static string rd
    {
        get { return _rd; }
    }

    private static string _rw = "RW";
    public static string rw
    {
        get { return _rw ; }
        set { _rw = value; }
    }
}

I know read-only class properties are possible in Python, but how I have not seen any examples of read-write class properties in Python. Is it possible? Basically I want:

class classproperty(object):

    def __init__(self, getter
            #, setter
        ):
        self.getter = getter
    #    self.setter = setter

    def __get__(self, instance, owner):
        return self.getter(owner)

    # Could there be a __set__ here?
    #vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
    #def __set__(self, instance, owner, value):
    #    self.setter(owner, value)
    #^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

class Foo(object):

    _ro = "RO"
    _rw = "RW"

    @classproperty
    def ro(cls):
        return cls._ro

    # How would you this?
    #vvvvvvvvvvvvvvvvvvvv
    #@classproperty.setter
    #^^^^^^^^^^^^^^^^^^^^
    #def rw(cls, value):
    #    cls._rw, value

# This is what I need
>>> Foo.ro
RO
>>> Foo.ro = 'X'     # Hypothetical Exception
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: class 'Foo' attribute 'ro' is not writable!
>>> Foo.rw
RW
>>> Foo.rw = 'NEW'
>>> Foo.rw
NEW
Community
  • 1
  • 1
Amal
  • 243
  • 1
  • 3
  • 8

1 Answers1

20

I think you want to use the property() built-in. http://docs.python.org/2/library/functions.html#property

While conventionally, it is used on an instance, I think you may be able to use it on a metaclass to achieve what you want.

class MetaFoo(type):
    _ro = "RO"
    _rw = "RW"

    def _get_ro(self):
        return self._ro
    def _get_rw(self):
        return self._rw
    def _set_ro(self, value):
        raise AttributeError("class 'Foo' attribute 'ro' is not writable!")
    def _set_rw(self, value):
        self._rw = value
    ro = property(_get_ro, _set_ro)
    rw = property(_get_rw, _set_rw)


class Foo(object):
    __metaclass__=MetaFoo


assert Foo.rw == "RW"
Foo.rw = 'NEW'
assert Foo.rw == "NEW"

assert Foo.ro == "RO"

try:
    Foo.ro = 'X'
except Exception as e:
    assert str(e) == "class 'Foo' attribute 'ro' is not writable!", str(e)
    assert type(e) == AttributeError
Joshua D. Boyd
  • 4,808
  • 3
  • 29
  • 44
  • 1
    That's great. This is the simplest answer I have seen. – Amal Dec 05 '12 at 14:31
  • When there are __metaclasses__defined, how could one add documentation strings to these class properties? – Amal Dec 05 '12 at 15:26
  • There are two ways to use `property()`. The I showed and as a decorator. The decorator form preserves doc strings. The way I showed, the docstring would be the fourth argument, while the third argument is a delete method for the propery. Again, see the python documentation link I included. – Joshua D. Boyd Dec 05 '12 at 16:51
  • 1
    Awesome. This also works with the @property decorator. 'self' in the metaclass should probably be 'cls' though (just for convention). – Rafe Mar 02 '13 at 20:37