© Jacob Zimmerman 2018
Jacob ZimmermanPython Descriptorshttps://doi.org/10.1007/978-1-4842-3727-4_3

3. What Are Descriptors Good For?

Jacob Zimmerman1 
(1)
New York, USA
 

Nothing is perfect in this world, and Python’s descriptors are no exception. Descriptors allow you to do some pretty cool things, but those cool things come at a cost. Here, we discuss the good and the bad.

Pros of Python Descriptors

Obviously we’re going to go over the good things about descriptors. Would there be an entire book about them if they couldn’t be considered a good thing?

Encapsulation

One of the most useful aspects of descriptors is that they encapsulate data so well. With descriptors, you can access an attribute the simple way using attribute access notation (a.x) while having more complex actions happen in the background. For example, a Circle class might have radius, diameter, circumference, and area all available as if they were attributes, but since they’re all linked, you only need to store one (we’ll use the radius for the example) and calculate the others based on it. But from the outside, they all look like attributes stored on the object.

Reuse of Read/Write Patterns

Using specialized descriptors, you can reuse code that you used with reading and/or writing of attributes. These can be used for repetitious attributes within the same class or attribute types shared by other classes as well. Some examples of reusable patterns are described in the following sections.

Lazy Instantiation

You can use descriptors to define a really simple syntax for lazily instantiating an attribute. There will be code provided for a nice lazy attribute implementation later in the book.

In the Circle example, the non-radius attributes, after having their caches invalidated, don’t need to calculate their values right away; they could wait until they’re needed. That’s laziness.

Validation

Many descriptors are written simply to make sure that data being passed in conforms to the class’ or attribute’s invariants. Such descriptors can usually be designed as handy decorators, too.

Again with the Circle example: all of those attributes should be positive, so all the descriptors could also make sure the value being set is positive.

Triggering Actions

Descriptors can be used to trigger certain actions when the attribute is accessed. For example, the observer pattern can be implemented in a per-attribute sense to trigger calls to the observer whenever an attribute is changed.

Last Circle example: all the “attributes” are based on the radius calculated lazily. In order to keep from having to calculate them every time, you could cache the result. Then, whenever one of them changes, it could trigger invalidating all the others’ caches.

Writing for the Class Level

Because descriptors are stored at the class scope instead of the instance scope, it allows you to do more robust things at the class level. For instance, descriptors make classmethod and staticmethod work, which will be explained in the next chapter.

Cons of Python Descriptors

As great as descriptors are, they come at a cost, just like just about everything else in programming.

Encapsulation

Wait… encapsulation was a pro. How can it also be a con? The problem is that you can hide incredible amounts of complexity behind something that just looks like attribute use. With getters and setters, the user at least sees that there’s a function being called, and plenty can happen in a single function call. But the user won’t necessarily expect that what is seemingly attribute access is causing something else to happen, too. Most of the time, this isn’t a problem, but it can get in the user’s way of trying to debug any problems, since clearly that code can’t be a problem.

Can Be Difficult To Write

It can be easy for the mind to get all twisted up when it comes to thinking about the fact that descriptors are stored at the class level, but are usually for dealing with attributes at the instance level. Besides that, there are a lot of considerations and common pitfalls to deal with when deciding how to save the represented attribute, whether you decide to do it on the descriptor or on the the object that the attribute is for. The descriptor-tools library was created specifically because of this.

Additional Objects

Because descriptors add another layer of indirection/abstraction to the mix, they also add at least one additional object in memory, along with at least one additional call stack level. In most cases, it’ll be more than one of each. This adds bloat that could at least be partially mitigated using getters and setters.

Summary

Descriptors are awesome, allowing for a variety of nice features that are good at hiding their complexity from users of your code, but you should definitely be aware that the power comes with cost.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.218.151.44