ReadOnly Attributes in Python

How to create read only attributes and restrict setting attribute values on object in python

There are different way to prevent setting attributes and make attributes read only on object in python. We can use any one of the following way to  make attributes readonly

  1. Property Descriptor
  2. Using descriptor methods __get__ and __set__
  3. Using slots  (only restricts setting arbitary attributes)

Property Descriptor

Python ships with built in function called property. We can use this function to customize the way attributes be accessed and assigned.

First I will explain you about property before I get you idea about how it is useful to make attribute readonly.

Typical signature of the function property is

 property([fget[, fset[, fdel[, doc]]]]

As you can see here this function take four arguments, those are

fget is a function for getting an attribute value. fset is a function for setting an attribute value. fdel is a function for deleting an attribute value. And doc creates a docstring for the attribute.

All these function are for the sake of single attribute. That is fget function will be called when you access/get the attribute. fset function will be called when you are trying to set the attribute.

Simple example

Instantiate Foo and try to play the instance attribute x

I hope, you got what exactly the function property is and how we use it. In many cases we use this property to hide actual attributes and abstract them with another name.

You can use property as decorator also. Something like

Now let’s come to actual thing how we make attribute readonly.

It’s simple you just don’t define setter for the property attribute. Let’s see the following example

Here, as we didn’t define setter for the property attribute. So python won’t allow setting that specific attribute even you can’t delete if you don’t define fdel. Thus, attribute becomes read only. Still you can access b._money  and you can set that attribute there is no restriction over setting this internal attribute.

Descriptor methods __get__ and __set__

These magic methods define descriptor for the object attribute. To get complete understanding and usage about descriptor magic methods, please check other article .

Like fget and fset functions that property function takes, __get__ is used to define behavior when descriptor’s value is retrieved. __set__ method is used to define behavior  when descriptor value is getting set(assigned). Where __delete__ is used to define behavior when descriptor is getting deleted.

To restrict setting attribute and make it readonly. You have to use __set__ magic method of descriptor and raise exception in it.

Let’s see the simple example demonstrating descriptor object and readonly attributes using descriptors

Lets see the result and trying to set speed attribute

As you can see here, we can’t set the attribute speed on instance v of Vehicle. Because we are restricting it in descriptor method __set__ of class Speed

Python __slots__

The basic usage of __slots__ is to save space in objects. Instead of having a dynamic dict that allows adding attributes to objects at anytime, there is a static structure which does not allow additions after creation. This will also gain us some performance due to lack of dynamic  attribute assignment. That is, it saves the overhead of one dict for every object that uses slots.

Think of you are creating lot of (hundreds, thousands) instances from the same class, this could be useful as memory and performance optimization tool.

If you are using __slots__ means you are defining static attributes on class. This is how we save memory and gain performance as there is not dynamic attribute assignment. Thus you can’t set new attributes on object.

You see, in the above example we are not able to set attribute c as it not given in __sots__. Any way it’s about restricting  assignment to new attributes and you can combine either above two methods to make existing attributes readonly.

 

References:

[1] __get__ and __set__ data descriptors don’t work on instance attributes http://stackoverflow.com/questions/23309698/why-is-the-descriptor-not-getting-called-when-defined-as-instance-attribute

[2] http://stackoverflow.com/questions/472000/usage-of-slots

One thought on “How to create read only attributes and restrict setting attribute values on object in python”

  1. Your ‘Vehicle’ class has a problem. The ‘distance’ and ‘time’ attributes are shared along all the instances.
    To avoid this, you must bind the value with the owner. A way to do that is using ‘owner.__dict__[“distance”]’ to store or get the distance value.

Leave a Reply

Your email address will not be published. Required fields are marked *