Getters and setters are methods used to access and modify the attributes of a class in a controlled manner. They provide encapsulation, allowing you to protect your data by controlling how it is accessed or modified. In Python, you can create getters and setters using traditional methods or the @property
decorator. This article explains these concepts with examples.
Directly accessing attributes of a class is possible in Python, but it is not always ideal. Getters and setters allow you to:
class Person: def __init__(self, name, age): self.__name = name # Private attribute self.__age = age # Private attribute def get_name(self): return self.__name def set_name(self, name): if name: self.__name = name else: print("Invalid name") def get_age(self): return self.__age def set_age(self, age): if age > 0: self.__age = age else: print("Invalid age") person = Person("Alice", 30) print(person.get_name()) person.set_name("Alicia") print(person.get_name()) print(person.get_age()) person.set_age(35) print(person.get_age())
In this example, get_name
and set_name
are used to access and modify the __name
attribute, while get_age
and set_age
do the same for __age
.
Python provides a more elegant way to create getters and setters using the @property
decorator. This approach allows you to define methods that act like attributes.
class Rectangle: def __init__(self, width, height): self.__width = width self.__height = height @property def width(self): return self.__width @width.setter def width(self, value): if value > 0: self.__width = value else: print("Width must be positive") @property def height(self): return self.__height @height.setter def height(self, value): if value > 0: self.__height = value else: print("Height must be positive") rectangle = Rectangle(4, 5) print(rectangle.width) rectangle.width = 10 print(rectangle.width) rectangle.height = -2 # Invalid value
In this example, the width
and height
properties use the @property
and @property_name.setter
decorators to define getters and setters.
Using @property
makes the code more readable and intuitive. It allows you to use getter and setter methods like attributes without parentheses.
Sometimes, you may want an attribute to be read-only. You can achieve this by defining only the getter method without a setter.
class Circle: def __init__(self, radius): self.__radius = radius @property def radius(self): return self.__radius circle = Circle(5) print(circle.radius) # circle.radius = 10 # Raises AttributeError
In this example, the radius
attribute is read-only because no setter method is defined.
Getters and setters are often combined to manage attributes with additional logic for validation or computation.
class Employee: def __init__(self, name, salary): self.__name = name self.__salary = salary @property def salary(self): return self.__salary @salary.setter def salary(self, value): if value > 0: self.__salary = value else: print("Salary must be positive") employee = Employee("John", 5000) print(employee.salary) employee.salary = 6000 print(employee.salary) employee.salary = -1000 # Invalid value
Here, the salary
property manages access and modification of the private attribute __salary
.
@property
decorator for a more Pythonic approach.Getters and setters are essential for encapsulation in object-oriented programming. Whether using traditional methods or the @property
decorator, they ensure data validation, protect sensitive attributes, and provide a cleaner interface for accessing and modifying class attributes.