Python Class Properties

Properties are setter/getter methods that set/get the value of a variable contained in the class.

Python
class Mass():
    def __init__(self, kilograms):
        self._kilograms = kilograms

    # This is the "getter" method for the property "kilograms"
    @property
    def kilograms(self):
        return self._kilograms;

    # The setter for "kilograms". Here, we guard against assigning a negative value
    # before storing it in the backing variable _kilograms
    @kilograms.setter
    def kilograms(self, massInKilograms):
        if (massInKilograms < 0):
            raise Exception("Mass cannot be negative.")
        self._kilograms = massInKilograms


aBall = Mass(25)
print('Mass in kilograms', aBall.kilograms)

aBall.kilograms = 100
print('Mass in kilograms', aBall.kilograms)

# Oops, the mass of something cannot be negative.
aBall.kilograms = -1

Output

Mass in kilograms 25
Mass in kilograms 100
Traceback (most recent call last):
  File "examples.py", line 25, in <module>
    aBall.kilograms = -1
  File "examples.py", line 25, in kilograms
    raise Exception("Mass cannot be negative.")
Exception: Mass cannot be negative.

Properties are defined as functions but used as instance variables. They are often used to do other things in addition to just getting and setting a value. A good example of a property getter is to guard against bad data, or data that is outside of some bounds, or to pre-process data, such as converting the value of a variable to a different unit of measure.

Using properties requires using the special decorators @property and @[name].setter where [name] is the property name exposed as a variable.

Let's extend the example above to allow the intenal value of "mass" to be expressed, and set, in units of grams or kilograms. This demonstrates how a backing variable can be used for two or more properties

Python
class Mass():
    def __init__(self, kilograms):
        self._kilograms = kilograms

    # The getter for the property "grams"
    @property
    def grams(self):
        return self._kilograms * 1000.0

    # The getter for the property "kilograms"
    @property
    def kilograms(self):
        return self._kilograms;

    # The setter for grams.
    @grams.setter
    def grams(self, massInGrams):
        if (massInGrams < 0):
            raise Exception("Mass cannot be negative.")
        self._kilograms = massInGrams / 1000.0

    # The setter for kilograms.
    @kilograms.setter
    def kilograms(self, massInKilograms):
        if (massInKilograms < 0):
            raise Exception("Mass cannot be negative.")
        self._kilograms = massInKilograms

aBall = Mass(25)
print('Mass in kilograms', aBall.kilograms)     # outputs 25
print('Mass in grams',     aBall.grams)         # outputs 25000