Python Code Example: Data abstraction – public, private, protected

Data Abstraction is a key concept in Object-Oriented Programming (OOP) that helps in hiding the implementation details while exposing only the necessary functionalities. In Python, abstraction is achieved using access specifiers:

Public (public) – Accessible from anywhere.
Protected (_protected) – Meant to be accessed within the class and subclasses.
Private (__private) – Cannot be accessed directly from outside the class.

In this example, we will create a BankAccount class demonstrating public, protected, and private attributes and their access control.


Python Code Example

class BankAccount:
    """Class representing a bank account with different access levels."""

    def __init__(self, account_holder, balance):
        """Constructor to initialize account holder and balance."""
        self.account_holder = account_holder  # Public attribute
        self._account_type = "Savings"  # Protected attribute
        self.__balance = balance  # Private attribute

    def deposit(self, amount):
        """Public method to deposit money into the account."""
        if amount > 0:
            self.__balance += amount
            print(f"Deposited ${amount:.2f}. New balance: ${self.__balance:.2f}")
        else:
            print("Deposit amount must be positive.")

    def withdraw(self, amount):
        """Public method to withdraw money from the account."""
        if 0 < amount <= self.__balance:
            self.__balance -= amount
            print(f"Withdrew ${amount:.2f}. New balance: ${self.__balance:.2f}")
        else:
            print("Insufficient funds or invalid amount.")

    def get_balance(self):
        """Public method to access private balance."""
        return self.__balance

# Creating an object of BankAccount
account = BankAccount("Alice", 1000)

# Accessing public attribute
print(f"Account Holder: {account.account_holder}")  # ✅ Allowed

# Accessing protected attribute (not recommended)
print(f"Account Type: {account._account_type}")  # ⚠️ Allowed, but should be accessed only in subclasses

# Trying to access private attribute (will raise an error)
# print(f"Balance: {account.__balance}")  # ❌ Not allowed (will raise an AttributeError)

# Correct way to access private attribute
print(f"Balance (via method): ${account.get_balance()}")  # ✅ Allowed through a public method

# Performing transactions
account.deposit(500)
account.withdraw(300)

Expected Output

Account Holder: Alice
Account Type: Savings
Balance (via method): $1000.00
Deposited $500.00. New balance: $1500.00
Withdrew $300.00. New balance: $1200.00

Code Explanation

  1. Public Attribute (account_holder)
    • Can be accessed from anywhere (account.account_holder).
  2. Protected Attribute (_account_type)
    • Conventionally meant for use within the class and subclasses but not enforced by Python.
    • Can still be accessed directly (account._account_type), though it is discouraged.
  3. Private Attribute (__balance)
    • Cannot be accessed directly (account.__balance).
    • Can only be accessed using a public method (get_balance()).
  4. Encapsulation and Data Security
    • The __balance attribute is private, ensuring that no external code can modify it directly.
    • Deposits and withdrawals are managed through public methods, enforcing business logic.

Why Use Data Abstraction?

Encapsulates data for security (prevents accidental modifications).
Controls access levels (public, protected, private).
Maintains structured, maintainable code.