Read-only attributes using properties?

Bengt Richter bokr at oz.net
Thu Nov 21 12:44:41 EST 2002


On 21 Nov 2002 05:27:55 -0800, wolfoxbr at hotmail.com (Roberto Amorim) wrote:

>I was thinking about trying to use the new properties on Python 2.2 to
>implement read-only attributes. So I tried the following:
>
>class MyException(Exception):
>	pass
>
>class TProp(object):
>	def __init__(self):
>		self.a = 0
>	def get_a(self):
>		return self.a
>	def set_a(self, v):
>		raise MyException
>	a = property(get_a, set_a, None, "Test a")
>
>t = TProp()
>print t.a
>t.a = 5
>
>I was expecting that the script would fail with an exception on the
>"t.a = 5" command. However, I was surprised to see the code fail on
>the attribution inside __init__ - that is, there is no "inner class
>scope", or direct access within the class itself, and no clear way to
>initialize the property. If the property is an alias to the real
>internal variable (call it size, for instance), it works, but then if
>I try to add a __slots__ list excluding the internal var and only
>adding the external reference (__slots__=("a")) it stops working
>again.
>
>Is there any other way to do that?
>
If by "that" you mean implementing a read-only property, just leave out the "write":

 >>> class TProp(object):
 ...     def __init__(self):
 ...             self._a = 0
 ...     def get_a(self):
 ...             return self._a
 ...     a = property(get_a, None, None, "Test a")
 ...

(I.e., just omit set_a and specify None in the corresponding property arg)

 >>> t = TProp()
 >>> print t.a
 0
 >>> t.a = 5
 Traceback (most recent call last):
   File "<stdin>", line 1, in ?
 AttributeError: can't set attribute

However, Python doesn't shut you out totally:

 >>> t._a = 5
 >>> print t.a
 5

You need a separate name for the actual data, because the property action triggers by way
of finding the property name as a class attribute when looking it up via an instance.

BTW, looking it up directly gets you the property object itself without triggering its action:

 >>> TProp.a
 <property object at 0x007AA470>


To illustrate further(I think this is ok, but I'm not sure if it's frowned upon):

 >>> TProp.b = property(lambda self: self._b, None, None, None)
 >>> t._b = 'aha'
 >>> t.b
 'aha'

 >>> t.b = 'oho'
 Traceback (most recent call last):
   File "<stdin>", line 1, in ?
 AttributeError: can't set attribute

Regards,
Bengt Richter



More information about the Python-list mailing list