Python Encapsulation

Encapsulation in object-oriented programming is the mechanism that bundles the data (attributes) and methods that operate on that data within one unit (a class). This bundling helps in protecting the data from direct access from outside the class and enforcing data integrity.

Basic Idea: Hiding Attributes


class BankAccount:
  def __init__(self, account_number, balance):
    self._account_number = account_number  # Use a single underscore for internal attribute
    self._balance = balance

  def deposit(self, amount):
    self._balance += amount

  def withdraw(self, amount):
    if self._balance >= amount:
      self._balance -= amount
    else:
      print("Insufficient funds")

  def get_balance(self):
    return self._balance

account = BankAccount("12345", 1000)
print(account.get_balance())  # Accessing through a method

# Trying to access the _balance directly will not work as intended:
# print(account._balance)  # This will work but is generally discouraged
    

Notice how _account_number and _balance are prefixed with an underscore. This is a convention to indicate that these attributes should be treated as internal to the BankAccount class. Direct access is discouraged. To access the balance, you use the get_balance() method.

Benefits of Encapsulation

  • Data Protection: Internal data is shielded from accidental modification or misuse from outside the class.
  • Maintainability: The code becomes more organized and easier to maintain because the internal structure is hidden and not accessible by any outside function.
  • Flexibility: The internal representation of the data can change (e.g., adding new attributes) without affecting code that interacts with the object through its methods.

Example with a read-only attribute


class Person:
    def __init__(self, name, age):
        self._name = name
        self._age = age

    def get_name(self):
        return self._name

    def get_age(self):
        return self._age

person = Person("Daniya", 19)
print(person.get_name()) # Output: Daniya
print(person.get_age())   # Output: 19

#Trying to modify the _name attribute will not work as intended
#person._name = "Bob"
    

Important Note

Encapsulation doesn't provide absolute protection. If needed, you can still access internal attributes if you know the attribute name (e.g., `account._balance`), though this practice is discouraged, as it defeats the purpose of encapsulation. Use access methods to gain access to the internal data values when necessary. The single underscore convention emphasizes that these attributes are intended for internal use.