Saturday 9 April 2016

Classes 3: Properties

Properties are the Pythonic way of implementing class members with associated getters and setters. In other object oriented languages like Java this is done from the beginning. In Python, the convention is to use getters and setters only when they are actually needed. For example when exception handling is required or when it becomes desirable to make a class member private. Otherwise the convention is to use the simplest implementation.

We can see the use of properties, getters and setters in action by modifying our bicycle example as follows.
#!/usr/bin/env python3

__project__= "Python Classes: The Bicycle Example"
__author__ = "Kevin Lynch"
__version__ = "$Revision: 3a $"
__date__ = "$Date: 2016/04/10 01:48:00 $"
__copyright__ = "Copyright (c) 2016 Kevin Lynch"
__license__ = "GPLv3"

class bicycle: # Defines the bicycle class.
        # Initialise bicycle with custom attributes.
        def __init__(self,frame,wheels):
                self.frameSet = frame
                self.wheelSet = wheels
                
        @property # Property decorator.
        def frameSet(self):
                return self.__frameSet

        @frameSet.setter # Setter method for the property frameSet.
        def frameSet(self,frame):
                if frame == "carbon":
                        self.__frameSet = frame
                elif frame == "steel":
                        self.__frameSet = frame
                else:
                        self.__frameSet = "wood"

        @property # Property decorator.
        def wheelSet(self):
                return self.__wheelSet

        @wheelSet.setter # Setter method for the property wheelSet.
        def wheelSet(self,wheels):
                if wheels == "carbon":
                        self.__wheelSet = wheels
                elif wheels == "alloy":
                        self.__wheelSet = wheels
                else:
                        self.__wheelSet = "wood"

# Global variables. Both reference the bicycle class.
bobsBike = bicycle("carbon","carbon")
suesBike = bicycle("steel","alloy")

print("Bob's Bike:\nFrame Set: " + bobsBike.frameSet + "\nWheel Set: " + bobsBike.wheelSet)
print("\n\nSue's Bike:\nFrame Set: " + suesBike.frameSet + "\nWheel Set: " + suesBike.wheelSet)

# We can still change things as before.
suesBike.frameSet = "plastic"

print("\n\nSue's Bike:\nFrame Set: " + suesBike.frameSet + "\nWheel Set: " + suesBike.wheelSet)

The only thing we have had to change in our bicycle example is the implementation of the bicycle class. In particular we have added our getters and setters. The getter method is decorated with the @property decorator and the setter method is decorated with the @<property name>.setter decorator. The rest of the program is unchanged.

This means that when we implement an attribute within a class in the simplest way possible. We can then change that implementation later without breaking the whole program. We use the same syntax to access properties as we do when accessing attributes or methods.

No comments:

Post a Comment