Python > Object-Oriented Programming (OOP) in Python > Encapsulation > Access Modifiers (public, protected, private - naming conventions)
Encapsulation and Access Modifiers in Python
This code snippet demonstrates encapsulation and access modifiers (public, protected, and private - through naming conventions) in Python using a simple `BankAccount` class. It illustrates how to control access to the internal state of an object.
Code Example
This code defines a `BankAccount` class with `account_number` (public), `_account_holder` (protected, using naming convention), and `__balance` (private, using naming convention) attributes. The `deposit` and `withdraw` methods modify the private `__balance`, while `get_balance` provides controlled access to it. The protected `_display_holder` shows a protected method as well.
class BankAccount:
def __init__(self, account_number, account_holder, balance):
self.account_number = account_number # Public attribute
self._account_holder = account_holder # Protected attribute (convention)
self.__balance = balance # Private attribute (convention)
def deposit(self, amount):
if amount > 0:
self.__balance += amount
print("Deposit successful.")
else:
print("Invalid deposit amount.")
def withdraw(self, amount):
if 0 < amount <= self.__balance:
self.__balance -= amount
print("Withdrawal successful.")
else:
print("Insufficient balance or invalid amount.")
def get_balance(self):
return self.__balance
def _display_holder(self):
print(f"Account Holder: {self._account_holder}")
# Example Usage
account = BankAccount("1234567890", "Alice Smith", 1000)
print(f"Account Number: {account.account_number}") # Accessing public attribute
print(f"Account Holder (Protected - Convention): {account._account_holder}") # Accessing protected attribute - use with caution!
#print(f"Balance: {account.__balance}") # This will raise an AttributeError because __balance is treated as private.
print(f"Balance: {account.get_balance()}") # Accessing private attribute via getter method
account.deposit(500)
account.withdraw(200)
print(f"Balance after transactions: {account.get_balance()}")
account._display_holder() #accessing protected method.
Concepts Behind the Snippet
Encapsulation is the bundling of data (attributes) and methods that operate on that data within a single unit (class). It helps in hiding the internal state of an object from the outside world and preventing direct access to it. Access modifiers (simulated in Python through naming conventions) control the visibility of class members.
Access Modifiers in Python (Naming Conventions)
Python doesn't have strict access modifiers like `public`, `protected`, and `private` as in other languages (e.g., Java, C++). Instead, it uses naming conventions: * Public: Attributes and methods without any prefix are considered public. They can be accessed from anywhere. * Protected: Attributes and methods with a single leading underscore (e.g., `_attribute`, `_method`) are considered protected. This indicates that they are intended for internal use within the class or its subclasses. While Python doesn't prevent external access, it's a signal to developers that they should use these members with caution. * Private: Attributes and methods with a double leading underscore (e.g., `__attribute`, `__method`) are considered private. Python performs name mangling on these members, making them harder (but not impossible) to access directly from outside the class. The name mangling mechanism effectively changes the attribute's name to `_ClassName__attribute`.
Real-Life Use Case
Imagine a `DatabaseConnection` class. You might want to expose a public method to execute queries, but hide the database connection details (host, username, password) as private attributes to prevent unauthorized access and modification.
Best Practices
Interview Tip
Be prepared to discuss encapsulation, access modifiers, and how Python simulates them using naming conventions. Explain the difference between public, protected, and private members and when to use each.
When to Use Them
Use encapsulation and access modifiers when you want to: * Control how data is accessed and modified. * Prevent unintended side effects from external code. * Hide implementation details. * Make your code more robust and maintainable.
Memory Footprint
Encapsulation itself doesn't directly affect memory footprint. However, using getter and setter methods can add a small overhead compared to directly accessing attributes. The memory footprint of the BankAccount class will primarily depend on the datatypes of account_number, account_holder and balance.
Alternatives
Python properties (`@property` decorator) provide a more Pythonic way to implement getters and setters, allowing you to control attribute access while maintaining a clean syntax.
Pros
Cons
FAQ
-
Why doesn't Python have true private access modifiers?
Python's philosophy emphasizes readability and ease of use. It's assumed that developers will follow the naming conventions to respect the intended visibility of class members. The lack of strict enforcement encourages a more collaborative and less restrictive coding style. It's often said that 'we are all consenting adults here'. -
Can I still access 'private' attributes in Python?
Yes, you can access 'private' attributes using name mangling (e.g., `object._ClassName__attribute`). However, it's strongly discouraged to do so as it violates the intended encapsulation and can lead to unexpected behavior. -
What is name mangling?
Name mangling is a process in which Python renames 'private' attributes (those with a double leading underscore) to avoid naming conflicts in subclasses. The name is changed to `_ClassName__attribute`.