Python Descriptors Tutorial

A useful technique for writing generic code that could be reused between the classes is supported by Python descriptors, or more commonly known as descriptors. They may sound close to the notion of inheritance, but they are not. This is a direct technique to capture access to attributes with a binding nature. Descriptors are a basic function of Python that governs a lot of the sorcery, concealed under the cover of the language. If you have ever felt that Python descriptors with little functional implementations are an advanced subject, then this tutorial is the ultimate platform to make you understand this powerful feature.

Descriptor Methods

To state it clearly, a class that implements __get_(), __set()_, or __delete()_ function of a descriptor protocol for an object is classified as a “Descriptor”. To govern the parameters of various classes that use the object as a reference, Python descriptors are made. Here are three specified methods, which will be used in descriptors:

__get__(): When you try to extract the data, the __get__() attribute is called, and whatever it provides is what would be provided to the code demanding the value of one variable. It is categorized as a non-data descriptor and is only readable.

__set__(): The function __set__() is called to adjust the parameter values, and nothing is returned to you by this function. It is known as a data descriptor that is not only readable but also writeable.

__delete__(): Whenever the parameter is removed from an object, the __delete__() function is called. It is known as a data descriptor that is not only readable but also writeable.

You only need to enforce the descriptor protocol if you’re using Python descriptors in your script. The utmost significant functions of the protocol are get() and set() having the subsequent signature.

__get__(self, obj, type=None) -> object
__set__(self, obj, value) -> None

self is the instance of the descriptor.
obj is an instance of the object to which your descriptor is connected.
type is the type of an object.


Here we have defined two classes. In the class Descriptor, we have defined descriptor methods. In the get() method, the self is the instance for the descriptor ‘val’, it will get a value ‘Geeks’ and stores it. Then it will make a string with ‘for’ attached between the provided attribute. class Descriptor(object):

def __get__(self, obj, objtype):
return “{}for{}”.format(self.val, self.val)

It will then return the value to the set() method. This function then checks for the value, whether it is a string or not. In case the value is a string, it will be saved into an attribute named ‘val’. If the value is not a string, it will throw an exception.

def __set__(self, obj, val):
if isinstance(val, str):
self.val = val
raise TypeError(“Name should be string”)

After that, the value will be get printed as a string ‘GeeksforGeeks’.

class GFG(object):
val = Descriptor()
g = GFG()
g.val = “Geeks”

When you try running this code, you will get the following output:


Purpose of Descriptors

Let’s describe a class named ‘home’ with three characteristics, namely: loc, area, and price. You may use the function __init__() to initialize the class attributes.

class home:

def __init__(self,loc,area,price):

Then, you can use the function __str__(), which could return the result of the three attributes that you might pass to the class when building the item. The __str__() function will return the string.

When you execute this code, it will display the seemingly correct output.

Now let’s try to change the price of the home to a negative value, as below, and execute the code.

There is no change at all, except for the negative sign, as shown in the output. Hang on! Something’s off here, isn’t it? How come the price of a home is negative. Python allows it because Python is a versatile development environment that specifically doesn’t allow type-checking.

Let’s initialize an ‘if’ statement in __init__() function to raise an exception if the value or price is less than zero.

As of now, you may notice that it performs well, and if the price is less than zero, the code generates a Value Error.

As we might understand, the __init_() function is a constructor, and is only invoked once when you make a class object. Therefore, later on, customized type-checking would fail. Python provides Descriptors that specialize in helping fix all of the above concerns. Now, let’s start using descriptors in the same example to understand it well.

The Descriptor class’ __init_() function has a local variable __price at 0. At the start of it, a double underscore implies that the parameter is private. It is used to differentiate the Descriptor class price parameter from the home class.

The __get__() method will return the price. The attribute instance contains h1, which is a descriptor instance. Attribute owner refers to the name of class ‘home’ and return the price.

The function __set__() has an attribute instance that contains h1, and a value to be assigned. Check is used to confirm the value. If the value is an integer, it will be printed out, otherwise, the code with throw a Type Error exception. If the value is below zero, the Value Error exception will be thrown into the code.

The __delete__() function is executed when the parameter attribute is removed from an object.

The home class stays the same, although the instance price of the Descriptor() class is added. In the __init_() function, add the price attribute to the instance price, and it will call the __set_() function.

While running this code, it will give you a Value Error because the price can never be zero.

Now try to execute the code with a string value.

It will throw a Type Error exception.

The existing instance value is overridden on the formation of a new instance since the descriptors are related to the class and not the instance. Take a look at below:

The first value has been overridden with the second one.


We can grasp why descriptors from Python have become such a fascinating topic and what kind of usage scenarios you can add them to by going through this tutorial.

About the author

Aqsa Yasin

Aqsa Yasin

I am a self-motivated information technology professional with a passion for writing. I am a technical writer and love to write for all Linux flavors and Windows.