Using property() as a Decorator
00:00
Using property()
as a Decorator. Decorators are everywhere in Python. They’re functions that take another function as an argument and return a new function with added functionality.
00:13
With a decorator, you can attach pre- and post-processing operations to an existing function. As you can see on-screen, the decorator syntax consists of placing the name of the decorator function with a leading @
symbol right before the definition of the function you want to decorate. In this code, @decorator
can be a functional class intended to decorate the function.
00:37
The syntax is equivalent to the following, now seen on-screen. The final line of code reassigns the name func
to hold the result of calling decorator()
with func
as an argument.
00:49 Note that this is the same syntax you used to create a property previously.
00:57
On-screen, you’ll see property()
being used as a decorator to create a Circle
class with the same functionality as the previous example where you used property()
as a function,
01:16
The decorator approach for creating properties requires defining a first method using the public name for the underlying managed attribute, which is .radius
in this case. This method should implement the getter logic.
01:32
These lines define the setter method for .radius
. In this case, the syntax is fairly different. Instead of using @property
again, you see @radius.setter
. Why do you need to do that?
01:48
Take another look at the dir()
output, of which a selected portion is shown on the slide on-screen. Besides .fget
, .fset
, .fdel
, and a bunch of other special attributes and methods, property
also provides .deleter()
, getter()
, and .setter()
. These three methods each return a new property.
02:10
When you decorate the second .radius()
method with @radius.setter
, you create a new property and reassign the class-level name .radius
to hold it.
02:20
This new property contains the same set of methods of the initial property, with the addition of the new setter method. Finally, the decorator syntax reassigns the new property to the .radius
class-level name.
02:36
The mechanism to define the deleter method is similar. This time you need to use the @radius.deleter
decorator. At the end of the process, you get a full-fledged property with the getter, setter, and deleter methods.
02:52
One question that may arise is how you can provide suitable docstrings for your properties when you use the decorator approach. If you look at Circle
on-screen, you’ll note that you’ve already done so by adding a docstring to the getter method.
03:07
This code looks fairly different from the getter and setter methods approach. Circle
now looks more Pythonic and clean. You don’t need to use method names such as ._get_radius
, ._set_radius
, and ._del_radius
anymore.
03:22 Now you can have three methods with the same clean and descriptive attribute-like name.
03:30
This new Circle
implementation works the same as the example seen previously.
03:39
You don’t need to use a pair of parentheses for calling .radius()
as a method. Instead, you can access .radius
as you would access a regular attribute, which is the primary use of properties.
03:51 They allow you to treat methods as attributes, and they take care of calling the underlying set of methods automatically.
04:10
Here’s a recap of some important points to remember when you’re creating properties with a decorator approach. The @property
decorator must decorate the getter method.
04:20
The docstring must go in the getter method. The setter and deleter methods must be decorated with the name of the getter method plus .setter
and .deleter
, respectively.
04:34
If you check your Circle
implementations so far, then you’ll note that their getter and setter methods don’t add any real processing on top of your attributes. In general, you should avoid turning attributes that don’t require extra processing into properties.
04:51 Using properties in those situations can make your code unnecessarily verbose, confusing to other developers, and slower than code based on regular attributes.
05:02
Unless you need something more than bare attribute access, don’t write properties. They’re a waste of CPU time, and more importantly, they’re a waste of your time. Finally, you should avoid writing explicit getter and setter methods and then wrapping them up in a property. Instead, use the @property
decorator.
05:22 That’s currently the most Python way to go.
05:27 In the next section of the course, you’ll see how to create properties that are read-only.
Become a Member to join the conversation.
Dawn0fTime on May 1, 2023
This is my new favorite sentence: “They’re functions that take another function as an argument and return a new function with added functionality.”