Locked learning resources

Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Locked learning resources

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

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.

Avatar image for Dawn0fTime

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.”

Become a Member to join the conversation.