DEV Community

Cover image for Python basics - Day 27
Sabin Sim
Sabin Sim

Posted on

Python basics - Day 27

Day 27 – Encapsulation & Property

Project: Build a “Bank Account System” that demonstrates encapsulation, private attributes, and the use of Python’s @property decorator.


01. Learning Goal

By the end of this lesson, you will be able to:

  • Understand encapsulation and why it matters in OOP
  • Use private attributes (_ and __) to hide internal data
  • Access private variables through getter/setter methods
  • Simplify code with the @property decorator
  • Create read-only properties for secure, immutable data

02. Problem Scenario

You are building a bank account system where each user’s balance must be private and protected.

Users should not modify balances directly — only through controlled methods that validate input.

Encapsulation ensures that sensitive data remains safe from misuse.


03. Step 1 – Encapsulation Basics

Encapsulation hides internal details of an object and exposes only the necessary interface.

In Python, attributes starting with _ or __ are treated as private by convention.

class Person:
    def __init__(self, name, age):
        self.name = name        # Public
        self.__age = age        # Private

    def get_age(self):
        return self.__age       # Access via method

p = Person("Sabin", 30)
print(p.name)        # Sabin
# print(p.__age)     # ❌ AttributeError
print(p.get_age())   # 30
Enter fullscreen mode Exit fullscreen mode

04. Step 2 – Getter and Setter Methods

Use getter and setter methods to safely access and modify private attributes.

class Account:
    def __init__(self, balance):
        self.__balance = balance

    def get_balance(self):
        return self.__balance

    def set_balance(self, amount):
        if amount >= 0:
            self.__balance = amount
        else:
            print("Invalid balance")

acc = Account(100)
print(acc.get_balance())   # 100
acc.set_balance(200)
print(acc.get_balance())   # 200
Enter fullscreen mode Exit fullscreen mode

05. Step 3 – Using @property

Python’s @property decorator allows you to create getter/setter functionality
while accessing attributes as if they were public.

class Account:
    def __init__(self, balance):
        self.__balance = balance

    @property
    def balance(self):          # Getter
        return self.__balance

    @balance.setter
    def balance(self, amount):  # Setter
        if amount >= 0:
            self.__balance = amount
        else:
            print("Invalid balance")

acc = Account(100)
print(acc.balance)   # 100
acc.balance = 300
print(acc.balance)   # 300
Enter fullscreen mode Exit fullscreen mode

Now you can access and modify balance naturally without breaking encapsulation.


06. Step 4 – Read-Only Property

Define only a getter (no setter) to make a property read-only.

class Circle:
    def __init__(self, r):
        self.__r = r

    @property
    def area(self):
        return 3.14 * self.__r * self.__r

c = Circle(5)
print(c.area)   # 78.5
# c.area = 100  # ❌ AttributeError: can't set attribute
Enter fullscreen mode Exit fullscreen mode

07. Step 5 – Practice Examples

Example 1: Temperature Validation

class Temperature:
    def __init__(self, celsius):
        self.__celsius = celsius

    @property
    def celsius(self):
        return self.__celsius

    @celsius.setter
    def celsius(self, value):
        if value >= -273:   # Absolute zero check
            self.__celsius = value
        else:
            print("Invalid temperature")

t = Temperature(25)
print(t.celsius)   # 25
t.celsius = -300   # Invalid temperature
Enter fullscreen mode Exit fullscreen mode

Example 2: Student with Read-only Grade

class Student:
    def __init__(self, name, grade):
        self.name = name
        self.__grade = grade

    @property
    def grade(self):   # Read-only property
        return self.__grade

s = Student("Anna", "A")
print(s.name, s.grade)   # Anna A
# s.grade = "B"  # ❌ AttributeError: can't set attribute
Enter fullscreen mode Exit fullscreen mode

08. Mini Project – Secure Bank Account

Build a simple bank account system using encapsulation and properties.

class BankAccount:
    def __init__(self, owner, balance):
        self.owner = owner
        self.__balance = balance

    @property
    def balance(self):
        return self.__balance

    @balance.setter
    def balance(self, amount):
        if amount >= 0:
            self.__balance = amount
        else:
            print("Invalid amount — balance cannot be negative.")

    def deposit(self, amount):
        if amount > 0:
            self.__balance += amount
            print(f"Deposited {amount}. New balance: {self.__balance}")
        else:
            print("Deposit must be positive.")

    def withdraw(self, amount):
        if 0 < amount <= self.__balance:
            self.__balance -= amount
            print(f"Withdrew {amount}. New balance: {self.__balance}")
        else:
            print("Invalid withdrawal amount.")

acc = BankAccount("Sabin", 1000)
acc.deposit(500)
acc.withdraw(200)
print("Final balance:", acc.balance)
Enter fullscreen mode Exit fullscreen mode

Output:

Deposited 500. New balance: 1500
Withdrew 200. New balance: 1300
Final balance: 1300
Enter fullscreen mode Exit fullscreen mode

09. Reflection

You have learned how to:

  • Use encapsulation to protect data integrity
  • Apply getter/setter methods for controlled access
  • Simplify with the @property decorator
  • Create read-only properties for immutable data
  • Apply these concepts in real-world systems (like banking)

Next → Day 28 – Inheritance + Polymorphism
Learn how to combine inheritance with polymorphism to design flexible, extensible class hierarchies.

Top comments (0)