ELI5: Python @property and setter

For this ELI5 I’m gonna go over the @property and setter decorators. In my objects tutorial I mentioned that you can access and alter the content of attributes directly, but this is not always ideal. In other words, these allow you to create “getter” and “setter” methods that are common in other programming languages.

@property a.k.a python getter

First we’ll go over the @property decorator, which allows us to define a “getter” method. By a “getter” I mean a method that gets the value of a property. I’ll start by dumping some code down and explain it line by line. This is going to be an object that handles “time” in hours and minutes.

class Time:
    def __init__(self, hour, minute):
        self._hour = hour
        self._minute = minute

    @property
    def hour(self):
        return self._hour

    @property
    def minute(self):
        return self._minute

So, first thing I’ll explain is the init method. You’ll see here that the attributes begin with an underscore (_) character. This is common practice in python to designate that the attribute is “private”, which means it shouldn’t be accessed by users directly. It doesn’t actually restrict anything though, it’s more of a polite suggestion to users.

Now, for the two @property decorated functions. There are very simple getters, all they do is return the values. What @property does specifically though is it allows you to call these methods without including brackets, let me show you what I mean:

- sampleTime = Time(12, 34)
- sampleTime.hour
12

As you can see, I was able to get the _hour value by typing .hour. You might be wondering why you would bother using this though – it isn’t actually doing anything differently than if we just use self.hour and self.minute in the init right? Well, the main answer is that it’ll gives you access to setters.

Python setter

A setter is simply a method for setting the value of an attribute. These are incredibly useful as it allows you to introduce sanity checking and other additional steps when a user changes an attribute in the object. Here is some sample code showing a setter for the minute attribute:

class Time:
    def __init__(self, hour, minute):
        self._hour = hour
        self.minute = minute

    @property
    def hour(self):
        return self._hour

    @property
    def minute(self):
        return self._minute

    @minute.setter
    def minute(self, value):
        if value < 60:
            self._minute = value
        else:
            raise ValueError

So, let’s jump right down to line 14. Here I name my method @minute.setter, this only works if there is a method named “minute” decorated by an @property already. This code will then check if the value the user is entering is less than 60 and if it isn’t it will throw a ValueError. This means that if a user tries to set the minute of the time to an invalid value it won’t let them.

Update: You’ll also notice that I have self.minute in the init instead of self._minute, this means that the init will also use the setter and throw an error when it’s too big. Thanks to Dean for suggesting this addition!

Conclusion

So, there you have it, a quick intro to @property and how you can use it to create a setter for your python objects. if you want to practice, try adding a getter and setter for “second” and a setter for “hour” in the code above.

The next ELI5 (and final for a while) will be on subclassing. Stay tuned!

This entry was posted in ELI5, Python, tutorial and tagged , . Bookmark the permalink.

2 Responses to ELI5: Python @property and setter

  1. Dean Powell says:

    Using your code I can successfully do this:

    sampleTime = Time(12, 62)

    This is because the @setter for “minute” is not called from the __init__ method. If you want to call an attribute’s @setter, you would need to do something like this in your code:

    class Time:
    def __init__(self, hour, minute):
    self._hour = hour
    self.minute = minute

    Note…no underscore (self.minute, not self._minute). This will force the __init__ method to call the setter method.

    • Roy says:

      Good suggestion Dean, thanks for the comment! I’ve updated my blog to point out that the setter can and should be used by other methods in the class!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.