In OOP, the convention is that properties are implemented with a getter and a setter.
We do this because it is considered poor practice for one class to directly modify the properties of another class, as that underminds the principle of Encapsulation. So instead, we explicitly call the getter or setter when we need to modify values from outside.
Why Getters and Setters Exist
Getter and setter methods act as controlled access points. A getter retrieves a value. A setter, on the other hand, updates that value. Instead of allowing outside code to change data freely, the class decides how interaction happens.
Thanks to this approach, the internal state stays protected, while the public interface remains clear and consistent.
A Simple Example Without Protection
Consider a basic class:

Here, name can be read or changed directly. This works for simple cases.
But hat happens when you need to validate that name isn’t empty? Or log every time it changes? Or compute a value on-the-fly? Direct attribute access gives you no control.
In cases like these, getter and setter methods help by letting your class manage how its data is accessed and modified.
Adding a Getter Method
A getter provides a safe way to read data.

The underscore signals that _name is internal. Outside code uses get_name() instead.

Adding a Setter Method
A setter method controls how data is updated.

Now the class enforces a rule before updating the value.

Using Properties for Cleaner Access
Python provides a cleaner approach to writing getters and setters using properties.
The property decorator in Python is a powerful tool that allows you to define getter and setter methods for class attributes, without the need to explicitly call them as methods.
To create a property in Python, you need to define a method and place the @property decorator right above it.
With the @property decorator, a getter method can be treated as an attribute.
While properties resemble attributes, they actually function like methods under the hood. The difference is that when you use a method, you always have to call it with parentheses. But you can access a property using dot notation, just like with a normal attribute.
So, why opt for properties instead of methods?
The key factors are readability and adaptability.
Properties help to make your code cleaner and simpler.
With properties you can start with public attribures and you always have the option of maintaining backward compatibility without breaking code.

Note: The @<attribute>.setter decorator is utilized to create a method that serves as a "setter" for a specific attribute. Properties can create read-only (getter) attributes by omitting this setter.

When to Use Getters and Setters in Python
In languages like Java, getters and setters are expected. Fields are private by default, and every access goes through methods. Python takes a lighter approach. Attributes are public by convention, and direct access is normal.
This is a design choice. Python assumes developers act responsibly. For most classes, a public attribute is enough. This helps readability and you have the option, with the help of properties, to add getters/setters only when you need them[link].
Understanding Why Getters and Setters are Important
Getter and setter methods give you flexibility. Rules can change without affecting external code, data remains consistent, and behavior stays predictable. It is a pattern that emphasizes thoughful design and clarity of purpose.
Wrapping It Up
Getters and setters act as gatekeepers for your class’s data. They let you enforce rules, calculate values, and maintain control.
Python’s approach is this: you’re not required to add getters and setters everywhere “just in case.” You add them when they solve a real problem.
This keeps your code readable while giving you flexibility when complexity arises.