Skip to main content

Creating a Class: Getter and Setter Pattern v.s. Property

 

Getter and Setter Pattern comes from OOP languages such as C++ and Java in order to adhere to 

  • Encapsulation
    • the bundling of data/attributes and methods. 
    • restricting access to implementation details and violating state invariants  

In Python it is considered unpythonic. Instead, use @property decorator instead 

Class without Getter and Setter 

# Basic method of setting and getting attributes in Python
# This has no Encapsulation because it directly accesses the attributes

class Celsius:
    def __init__(self, temperature=0):
        self.temperature = temperature

    def to_fahrenheit(self):
        return (self.temperature * 1.8) + 32


# Create a new object
human = Celsius()

# Set the temperature
human.temperature = 37

# Get the temperature attribute
print(human.temperature)

# Get the to_fahrenheit method
print(human.to_fahrenheit())

>> 37
>> 98.60000000000001

 

Getter and Setter Pattern 

  • Class Attributes... 
    • are variables where you can access through the instance, class, or both. 
    • holds an internal state.  
    • Two ways to access class attributes:
      1. Directly (breaks encapsulation) 
        • If accessed directly, they become part of Public API
        • Only use if sure that no behavior (methods) will ever be attached to the variables  (@dataclass?)
        • Changing implementation will be problematic:
          • Converting stored attribute -> computed attribute. Want to be able to store attributes instead of recomputing each time 
        • No internal implementation 
      2. Methods (ideal) 
        • Two methods to respect encapsulation
          • Getter: Allows Access
          • Setter: Allows Setting or Mutation 
  • Implementation
    1. Making attributes Non-public
      • use underscore in variable name ( _name ) 
    2. Writing Getter and Setter Methods for each attribute
      • In a class, __init__ is the attributes (variables)
# Making Getters and Setter methods
# PRO: Adheres to Encapsulation since get/set methods is used to change the attributes instead of direct access
# PRO: Adheres to a faux Information Hiding since converting temperature to _temperature, but no private/protected vars in Python
# CON: Has more code to change

class Celsius:
    def __init__(self, temperature=0):
        self.set_temperature(temperature)

    def to_fahrenheit(self):
        return (self.get_temperature() * 1.8) + 32

    # getter method
    def get_temperature(self):
        return self._temperature

    # setter method
    def set_temperature(self, value):
        if value < -273.15:
            raise ValueError("Temperature below -273.15 is not possible.")
        self._temperature = value


# Create a new object, set_temperature() internally called by __init__
human = Celsius(37)

# Get the temperature attribute via a getter
print(human.get_temperature())

# Get the to_fahrenheit method, get_temperature() called by the method itself
print(human.to_fahrenheit())

# new constraint implementation
human.set_temperature(-300)

# Get the to_fahreheit method
print(human.to_fahrenheit())

>> 37
>> 98.60000000000001
>> Traceback (most recent call last):
>>  File "<string>", line 30, in <module>
>>  File "<string>", line 16, in set_temperature
>> ValueError: Temperature below -273.15 is not possible.