1. Properties
Welcome back! In this last video, you'll learn about properties, which are a special kind of attribute that allow customized access.
2. Changing attribute values
In the beginning of Chapter 1, you worked with an Employee class where you defined methods like set_salary that were used to set the values for attributes. Later, you learned about using the constructor to initialize the attributes .
You also learned that you can access and change the attributes directly by assignment. But this means that with a simple equality we can assign anything to salary: a million, a negative number, or even the word "Hello". Salary is an important attribute, and that should not be allowed.
3. Changing attribute values
So how do we control attribute access, validate it or even make the attribute read-only? We could modify the set_salary method, but that wouldn't help, because we could still use the dot syntax and assignment via equality.
4. Restricted and read-only attributes
There is a precedent for such attribute management with classes that you already know. For example, if you have a pandas DataFrame with two columns, you can set the columns attribute to a list of 2 strings -- new names for the columns. But if you try to set the attribute to a list of different length, you'd get an error.
Or, consider the shape attribute -- it cannot be changed at all!
5. @property
We can implement similar behavior using the property decorator. Start by defining an "internal" attribute that will store the data. As we learned in the previous video, it is recommended to start the name with one leading underscore.
Here, we defined a underscore-salary attribute.
Next, we define a method whose name is the exact name we'd like the restricted attribute to have, and put a decorator "property" on it. In our case that method is called salary, without underscore, because that's how we'd like to refer to it. If we were writing a DataFrame class, this could be "columns", or "shape".
The method just returns the actual internal attribute that is storing the data.
To customize how the attribute is set, we implement a method with a decorator "attribute name"-dot-setter: salary-dot-setter in our case. The method itself is again named exactly the same as the property -- salary - and it will be called when a value is assigned to the property attribute.
It has a self argument, and an argument that represents the value to be assigned.
Here we raise an exception if the value is negative, otherwise change the internal attribute.
So there are two methods called salary -- the name of the property -- that have different decorators. The method with property decorator returns the data, and the method with salary dot setter decorator implements validation and sets the attribute.
6. @property
How does this work in practice? We can use this property just as if it was a regular attribute (remember the only real attribute we have is the internal underscore-salary).
Use the dot syntax and equality sign to assign a value to the salary property. Then, the setter method will be called. If we try to assign a negative value to salary, an exception will be raised.
7. Why use @property?
Properties are useful because the user of your class will not have to do anything special. They won't even be able to distinguish between properties and regular attributes. You, on the other hand, now have some control over the access.
8. Other possibilities
There are a few other things you can do with properties: if you do not define a setter method, the property will be read-only, like Dataframe shape. A method with an attribute-name-dot-getter decorator will be called when the property's value is just retrieved, and the method with the attribute-name-dot-deleter -- when an attribute is deleted.
9. Let's practice!
Alright! Time for you to create some properties by yourself.