10: Advanced Attributes

Summary

  • Name mangling can provide a private attribute that is difficult to access accidentally

  • Using closure you can create a private variable

  • Properties have getter, setter and delete functions which are called when you try to work with the attribute

  • You can create a private property using the property object and closure

  • The property object has additional methods which allow it to be used as a decorator

Program

"""
Program: Advanced Encapsulation Techniques in Python

This program demonstrates:
1. Name mangling for private attributes
2. Closures to create private variables
3. Properties with getter, setter, and deleter
4. Private properties using closures
5. Using property() and decorator syntax

Author: Your Name
"""

# --------------------------------------------------
# 1. Name Mangling (Pseudo-private attributes)
# --------------------------------------------------

class BankAccount:
    def __init__(self, owner, balance):
        self.owner = owner
        self.__balance = balance  # Name mangling: _BankAccount__balance

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

    def get_balance(self):
        return self.__balance


# --------------------------------------------------
# 2. Closure for Private Variable
# --------------------------------------------------

def counter():
    count = 0  # private variable via closure

    def increment():
        nonlocal count
        count += 1
        return count

    return increment


# --------------------------------------------------
# 3. Properties with Getter, Setter, Deleter
# --------------------------------------------------

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

    def get_celsius(self):
        print("Getting value...")
        return self._celsius

    def set_celsius(self, value):
        print("Setting value...")
        if value < -273.15:
            raise ValueError("Temperature below absolute zero is not possible.")
        self._celsius = value

    def del_celsius(self):
        print("Deleting value...")
        del self._celsius

    # property object
    celsius = property(get_celsius, set_celsius, del_celsius)


# --------------------------------------------------
# 4. Private Property Using Closure + property()
# --------------------------------------------------

def create_person(name, age):
    _age = age  # private via closure

    def get_age(self):
        return _age

    def set_age(self, value):
        nonlocal _age
        if value < 0:
            raise ValueError("Age cannot be negative")
        _age = value

    def del_age(self):
        nonlocal _age
        print("Deleting age...")
        _age = None

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

        age = property(get_age, set_age, del_age)

    return Person(name)


# --------------------------------------------------
# 5. Property Decorator Syntax
# --------------------------------------------------

class Rectangle:
    def __init__(self, width, height):
        self._width = width
        self._height = height

    @property
    def area(self):
        """Getter: Calculates area"""
        return self._width * self._height

    @area.setter
    def area(self, value):
        """Setter: Adjust width assuming height stays constant"""
        print("Setting area...")
        self._width = value / self._height

    @area.deleter
    def area(self):
        """Deleter"""
        print("Deleting dimensions...")
        del self._width
        del self._height


# --------------------------------------------------
# MAIN DEMONSTRATION
# --------------------------------------------------

if __name__ == "__main__":

    print("---- Name Mangling Example ----")
    acc = BankAccount("Alice", 1000)
    acc.deposit(500)
    print("Balance:", acc.get_balance())

    # Accessing mangled name (not recommended)
    print("Access via mangled name:", acc._BankAccount__balance)

    print("\n---- Closure Example ----")
    my_counter = counter()
    print(my_counter())
    print(my_counter())
    print(my_counter())

    print("\n---- Property (Getter/Setter/Deleter) ----")
    temp = Temperature(25)
    print(temp.celsius)
    temp.celsius = 30
    print(temp.celsius)
    del temp.celsius

    print("\n---- Private Property with Closure ----")
    person = create_person("Bob", 20)
    print(person.name, person.age)
    person.age = 25
    print("Updated age:", person.age)

    print("\n---- Property Decorator Example ----")
    rect = Rectangle(4, 5)
    print("Area:", rect.area)
    rect.area = 50
    print("New width after setting area:", rect._width)
    del rect.area

Program Output

---- Name Mangling Example ----
Balance: 1500
Access via mangled name: 1500

---- Closure Example ----
1
2
3

---- Property (Getter/Setter/Deleter) ----
Getting value...
25
Setting value...
Getting value...
30
Deleting value...

---- Private Property with Closure ----
Bob 20
Updated age: 25

---- Property Decorator Example ----
Area: 20
Setting area...
New width after setting area: 10.0
Deleting dimensions...