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:
- 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
- Methods (ideal)
- Two methods to respect encapsulation
- Getter: Allows Access
- Setter: Allows Setting or Mutation
- Two methods to respect encapsulation
- Directly (breaks encapsulation)
- Implementation
- Making attributes Non-public
- use underscore in variable name ( _name )
- Writing Getter and Setter Methods for each attribute
- In a class, __init__ is the attributes (variables)
- Making attributes Non-public
# 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.