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

Unlock This Lesson

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

Unlock This Lesson

Hint: You can adjust the default video playback speed in your account settings.
Hint: You can set your subtitle preferences in your account settings.
Sorry! Looks like there’s an issue with video playback 🙁 This might be due to a temporary outage or because of a configuration issue with your browser. Please refer to our video player troubleshooting guide for assistance.

Replacing Getters and Setters With More Advanced Tools

00:00 Using More Advanced Tools. Up to this point, you’ve learned how to create bare-bones getter and setter methods to manage the attributes of your classes. You’ve also learned that properties are the Pythonic way to approach the problem of adding functional behavior to existing attributes.

00:16 In this part of the course, you’ll learn about other tools and techniques that you can use to replace getter and setter methods in Python. Descriptors are an advanced Python feature that allow you to create attributes with attached behaviors in your classes.

00:30 To create a descriptor, you need to use the descriptor protocol, particularly the .__get__() and .__set__() special methods. Descriptors are pretty similar to properties.

00:41 In fact, a property is a special type of descriptor. However, regular descriptors are more powerful than properties and can be reused through different classes.

00:52 To illustrate how to use descriptors to create attributes with functional behavior, let’s say you need to continue developing your Employee class.

01:00 This time, you need an attribute to store the date on which an employee started to work for the company.

01:15 In this update, you added another property to Employee. This new property will allow you to manage the start date of each employee.

01:31 Again, the setter method converts the date from a string to a date object.

01:44 The class works as expected. However, it does start to look repetitive and boring, so you decide to refactor the class. You notice that you are doing the same operation in both date-related attributes, and you think of using a descriptor to pack the repetitive functionality.

02:08 In this update, you create a Date descriptor to manage date-related attributes. The descriptor has a .__set_name__() method that automatically stores the attribute name.

02:20 It also has .__get__() and .__set__() methods that work as the attribute’s getter and setter, respectively.

02:38 birth_date and start_date class variables are defined, and then the class is initialized in the familiar manner.

03:02 ._name is then defined as a property, as seen earlier in the course.

03:13 The two implementations of Employee work similarly. This code is cleaner and less repetitive than the previous version. Go ahead and give them a try.

03:26 In general, if you find yourself cluttering up your classes with similar property definitions, then you should consider using a descriptor instead. Another way to replace traditional getter and setter methods in Python is to use the .__setattr__() and .__getattr__() special methods to manage your attributes.

03:45 Consider the following example, which defines a Point class. The class automatically converts the input coordinates into floating-point numbers.

04:01 The initializer of Point takes two coordinates, x and y. The .__getattr__() method returns the coordinate represented by name.

04:12 To do this, the method uses the instance namespace dictionary, .__dict__. Note that the attribute’s final name will have an underscore preceding whatever you pass in name. Python automatically calls .__getattr__() whenever you access an attribute of Point using dot notation.

04:30 The .__setattr__() method adds or updates attributes. In this example, .__setattr__() operates on each coordinate and converts it into a floating-point number using the built-in float() function. Again, Python calls .__setattr__() whenever you run an assignment operation on any attribute of the containing class. On-screen, you can see how the class works in practice.

05:04 The Point class automatically converts coordinate values into floating-point numbers. You can access the coordinates, x and y, as you would any other regular attribute.

05:14 However, access and mutation operations go through .__getattr__() and .__setattr__(), respectively. Note that Point allows you to access coordinates as public attributes.

05:25 However, it stores them as non-public attributes. You can confirm this behavior with the built-in dir() function.

05:42 The example in this section is a little bit unusual, and you probably won’t use something similar in your own code. However, the tools that you’ve used in the example allow you to perform validations or transformations on attribute access and mutation, just like getter and setter methods do. In a sense, .__getattr__() and .__setattr__() are a generic implementation of the getter and setter pattern. Under the hood, these methods work as getters and setters that support regular attribute access and mutation in Python. In the next section of the course, you’ll take a look at some of the factors you should think about when deciding which of the techniques you’ve seen in this course will be used in your code.

Become a Member to join the conversation.