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

Choosing Between Getters and Setters or Properties

00:00 Choosing Between Getters and Setters or Properties. In real-world coding, you’ll find a few use cases where getter and setter methods can be preferred over properties, even though properties are generally the Pythonic way to go.

00:13 For example, getter and setter methods may be better suited to deal with situations in which you need to run costly transformations on attribute access or mutation, take extra arguments and flags, use inheritance, raise exceptions related to attribute access and mutation, and facilitate integration in heterogeneous development teams.

00:35 In this section of the course, you’ll dive into these use cases and why getter and setter methods can be preferable to properties. You should avoid hiding slow operations behind a Python property.

00:47 The users of your API will expect attribute access and mutation to perform in a regular manner. In other words, they will expect these operations to happen instantaneously and without side effects.

00:59 Going too far away from that expectation will make your API odd and unpleasant to use, violating the least surprise principle. Additionally, if your users repeatedly access and mutate your attributes in a loop, then their code can involve too much overhead, which may produce huge and unexpected performance issues. In contrast, traditional getter and setter methods make it explicit that accessing or mutating a given attribute happens through a method call. Indeed, your users will be aware that calling a method can take time, and the performance of their code can vary significantly because of that.

01:33 Making these facts explicit in your API can help minimize your users’ surprise when they access and mutate attributes in their code. In short, if you’re going to use a property to manage an attribute, then make sure that the methods behind the property are fast and don’t cause side effects. In contrast, if you’re dealing with slow accessor or mutator methods, then favor traditional getters and setters over properties.

02:01 Unlike Python properties, traditional getter and setter methods allow for more flexible attribute access and mutation. For example, let’s say you have a Person class with a .birth_date attribute.

02:14 This attribute should be constant throughout a person’s lifetime. Therefore, you decide that the attribute will be read-only. However, because there is a thing called human error, you’ll face cases in which someone made a mistake when entering a birth date of a given person.

02:29 You can solve this problem by providing a setter method that takes a force flag, as seen on-screen.

02:51 You provide traditional getter and setter methods for the .birth_date attribute in this example.

02:58 The setter method takes an extra argument called force, which allows you to force the modification of a person’s date of birth. Note that traditional setter methods typically don’t take more than one argument.

03:10 This example may look odd or even incorrect to some developers. However, its intention is to showcase a technique that can be useful in some situations.

03:22 On-screen, you can see the class working

03:40 When you try to modify Jane’s date of birth using .set_birth_date() without setting force to True, you get an AttributeError signaling that the attribute can’t be set.

03:50 In contrast, if you set force to True, then you’ll be able to update Jane’s date of birth to correct any errors that occurred when the date was entered.

03:58 It’s important to note that Python’s properties don’t accept extra arguments in their setter methods. They just accept the value to be set or updated.

04:10 One issue with Python properties is that they don’t do well in inheritance scenarios. For example, let’s say you need to extend or modify the getter method of a property in a subclass. In practice, there’s no safe way to do this.

04:24 You can’t just override the getter method and expect the rest of the property’s functionality to remain the same as in the parent class. This issue occurs because the getter and setter methods are hidden inside the property. They’re not inherited independently, but as a whole. Therefore, when you override the getter method of a property inherited from a parent class, you override the whole property including its setter method and the rest of the internal components. An example class hierarchy is seen on-screen.

05:21 Here, you override the getter method of the .name property in Employee.

05:28 This way, you are implicitly overriding the whole .name property, including the setter functionality.

05:53 Now, .name is a read-only property because the setter method of the parent class wasn’t inherited, but was overridden by a completely new property. You didn’t want to do that, so how can you solve this inheritance issue?

06:08 If you use traditional getter and setter methods, then the issue won’t happen.

06:27 This version of Person provides independent getter and setter methods.

06:36 Employee subclasses Person, overriding the getter method for the same attribute. This fact doesn’t affect the setter method, which Employee successfully inherits from the parent class, Person.

06:50 On-screen, you can see the new version of Employee working.

07:05 Now Employee is completely functional. The overridden getter method works as expected, and the setter method also works because it was successfully inherited from Person.

07:19 Most of the time, you won’t expect an assignment statement as seen on-screen to raise an exception. In contrast, you can expect methods to raise exceptions in response to errors.

07:29 In this regard, traditional getter and setter methods are more explicit than properties. This example seen on-screen doesn’t look like something that can raise an exception. It looks and should behave like a regular attribute assignment.

07:43 On the other hand, this does look like something that can raise an exception, perhaps a ValueError, because the input value isn’t a valid URL for a website.

07:53 In this example, the setter method is more explicit. It clearly expresses the code’s possible behavior. As a rule of thumb, you should avoid raising exceptions from your Python properties unless you’re using a property to provide read-only attributes.

08:08 If you ever need to raise exceptions on attribute access or mutation, then you should consider using getter and setter methods instead of properties. In these cases, using getters and setters will reduce the user surprise and make your code more aligned with common practices and expectations.

08:26 Providing getter and setter methods is common practice in many well-established programming languages. If you’re working on a Python project with a team of developers who come from other language backgrounds, then it’s pretty likely that the getter and setter pattern will look more familiar to them than Python properties. In this kind of team, using getters and setters can facilitate the integration of new developers into the team. Using the getter and setter method can also promote API consistency.

08:53 It allows you to provide an API based on method calls rather than an API that combines method calls with direct attribute access and mutation. Often, when a Python project grows, you may need to migrate the project from Python to another language.

09:08 The new language may not have properties, or they may not behave as Python properties do. In these situations, using traditional getters and setters from the beginning would make future migrations less painful.

09:21 In all of the situations you’ve seen in this part of the course, you should consider using traditional getter and setter methods instead of properties in Python.

09:31 In the next section of the course, you’ll take a look back at what you’ve learned.

Avatar image for Benjamin Kandel

Benjamin Kandel on Jan. 9, 2024


First, thanks for a very valuable course! It helps deciding which strategy to use when building a class, depending on the level of complexity you are targeting. There may be a typo in the slide with the “site_url” example: I would expect the first example to be

site.url = "123"

instead of

site_url = "123"

Am I right?

Become a Member to join the conversation.