Introduction
Imagine you’re building a digital banking app and you’ve created a simple BankAccount class. You’ve added a balance attribute to track the funds in each account. But here’s the problem: anyone can change that balance directly from outside the class. That’s not just bad design — it’s dangerous. In the world of programming, especially when handling sensitive data like money, protecting internal attributes from unintended changes is crucial. So, how do we allow safe read and controlled write access to balance without exposing it completely?

Encapsulation: The Key to Controlled Access
Python offers a clean way to manage attribute access using encapsulation, one of the core principles of object-oriented programming.
Step 1: Make balance a private attribute
To start, rename balance as _balance or __balance. This tells others (and Python) that it’s meant to be private:
class BankAccount:
def __init__(self, initial_amount):
self.__balance = initial_amount

Step 2: Use property decorators for controlled access
To allow reading the balance without letting it be modified directly, we use the @property decorator:
@property
def balance(self):
return self.__balance
Now, account.balance can be read, but not changed directly. If someone tries account.balance = 1000, it will raise an error.
Step 3: Create a setter for controlled modification
If you want to allow balance updates only through proper rules (like not allowing negative deposits or unauthorized changes), define a setter:
@balance.setter
def balance(self, amount):
if amount >= 0:
self.__balance = amount
else:
raise ValueError("Balance cannot be negative.")
This allows safe, validated updates to balance.
Optional: Use methods for operations
For even better control, provide methods like deposit() or withdraw() instead of exposing a setter:
def deposit(self, amount):
if amount > 0:
self.__balance += amount
else:
raise ValueError("Deposit must be positive.")
def withdraw(self, amount):
if 0 < amount <= self.__balance:
self.__balance -= amount
else:
raise ValueError("Invalid withdrawal amount.")
This way, you’re not just protecting data — you’re guiding how it’s used.

Conclusion
Direct access to sensitive attributes like balance can lead to bugs, vulnerabilities, and misuse. By using Python’s property decorators and private variables, you can shield your internal data while still offering a clean, readable interface. Encapsulation isn’t just about hiding — it’s about protecting your logic and ensuring safe interactions with your class. If you’re building secure, maintainable applications, this small shift in design makes a big difference.