Analysis of Descriptors

Learn how Python uses descriptors internally and how to use descriptors in decorators.

We have seen how descriptors work so far and explored some interesting situations in which they contribute to clean design by simplifying their logic and leveraging more compact classes.

By this point, we've learned that by using descriptors, we can achieve cleaner code, abstracting away repeated logic and implementation details. But how do we know our implementation of the descriptors is clean and correct? What makes a good descriptor? Are we using this tool properly or overengineering with it?

Let’s analyze descriptors in order to answer these questions.

How Python uses descriptors internally

What makes a good descriptor? A simple answer would be that a good descriptor is pretty much like any other good Python object. It is consistent with Python itself. The idea that follows this premise is that analyzing how Python uses descriptors will give us a good idea of good implementations so that we know what to expect from the descriptors we write.

We will see the most common scenarios where Python itself uses descriptors to solve parts of its internal logic, and we will also discover elegant descriptors and that have been there in plain sight all along.

Functions and methods

The most resonating case of an object that is a descriptor is probably a function. Functions implement the __get__ method, so they can work as methods when defined inside a class.

In Python, methods are just regular functions, only they take an extra argument. By convention, the first argument of a method is named self, and it represents an instance of the class that the method is being defined in. Then, whatever the method does with self would be the same as any other function receiving the object and applying modifications to it.

In other words, when we define something like this:

Get hands-on with 1200+ tech skills courses.