Properties and Descriptors
00:00 In the previous lesson, you learned more about Python attributes. In this lesson, you’ll learn other ways of accessing an object’s content. Say you wanted to have a method, but you wanted it to look like an attribute.
Inside the method, whatever I return will be the property’s value. Here I’m concatenating the first and last name together. Note how I’m accessing those attributes using
self inside the f-string.
01:24 This method is horribly Western-centric. The whole concept of first and last name is very European. Google falsehoods programmers believe about names for an education on these biases, or look up the RadioLab podcast episode called “Null” about the problems people with that last name have in the modern world. Anyhow, I’ll step off my soapbox.
02:23 Well, that codebase uses properties as the public interface. Almost all attributes have underscores, while the property exposes the actual value. In some cases, this might just be a developer quirk. Hey, you all have them.
One reason for doing this has to do with caching. Say you had a value that had some complications to calculate. You could initialize it to
None, and then the first time someone used it, do the calculation.
You can use a similar mechanism for trapping the setting of a value. To do this, you decorate the method with the name of the attribute, then
.setter. This mechanism allows you to perform side effects when a value is set, for example. You can perform other calculations, update that cache I was talking about, or do error checks on the value.
03:48 All of these things could equally be done with a method, and in fact, in a lot of other languages, having getter and setter methods is common. This really is just syntactical sugar, but it can make your code a little more readable.
A common pattern you’ll find in code is to pass a value to
.__init__() that gets stored in the class. Have that value stored as a non-public attribute, and then have a property with the same name but without the underscore and then a corresponding setter for that value. Inside the setter, you’re actually setting the non-public attribute as well as doing any error checking or other work, but from the perspective of the programmer using the object, it just looks like an attribute.
And this is what a setter decorator looks like. Note that it uses the same name as the property that you’re setting and then the
.setter. Remember, the property method takes no additional arguments. Well, the setter does need an argument: the new value being set.
05:26 If you’re used to Python, you might notice there’s something a little weird going on here with the name. Both the property and the setter methods are named radius. Normally, this wouldn’t be allowed in Python.
05:37 Python doesn’t support method overloading in the same class. But decorators are kind of a special case. Whenever you see a decorator, it’s actually wrapping the thing you’re decorating with a function.
It sort of hits home the fact that this is a setter for radius. You can call the method anything. Because it’s wrapped, it doesn’t really matter. Inside the method, I’m going to use the setter to do a little bit of an error checking. Here, I’m checking whether or not the contents of
.value is either an
int or a
float and is a positive number.
If you haven’t come across the notation with the pipe operator before, it was added in Python 3.10. It saves some typing. In the old days, you’d have to
or together two calls to
isinstance(). Isn’t progress grand?
Well, if the value being set isn’t an
int or a
float or it’s less than zero, I raise a
ValueError to tell them they can’t do that. If everything is okay, then I store the value on the non-public attribute. Let’s create a circle.
Again, you can do this with methods, but this is so very clean. Programmers using
Circle don’t have to think about it. They can just use the radius naturally, and yet you still get all the advantages of a method that checks for illegal values. Okay, you’ve seen a bunch having to do with attributes.
Become a Member to join the conversation.