@property, @setter, @deleter) позволяют контролировать доступ к атрибутам класса.
  @property определяет логику при чтении атрибута, позволяя выполнять валидацию или преобразование данных.
  @setter контролирует запись в атрибут, обеспечивая проверку типов, ограничение диапазонов значений или логику изменения других атрибутов.
  @deleter определяет поведение при удалении атрибута, что может быть использовано для предотвращения случайного удаления важных данных.
  _ или __) для ограничения доступа извне класса, инкапсулируя логику и предотвращая прямое изменение состояния объекта.
Для контроля доступа и безопасности в классе Python можно эффективно использовать свойства (properties) и методы.
Свойства (Properties):
Свойства позволяют инкапсулировать атрибуты класса и контролировать доступ к ним. Они предоставляют возможность выполнять дополнительные действия при чтении, записи или удалении атрибута.  Это достигается с помощью декораторов @property, @, и @.
Пример:
class Employee:
    def __init__(self, name, salary):
        self._name = name  # Protected attribute
        self._salary = salary # Protected attribute
    @property
    def salary(self):
        """Getter для зарплаты.  Предотвращает прямой доступ и позволяет при чтении добавить логику."""
        print("Получение зарплаты...")
        return self._salary
    @salary.setter
    def salary(self, new_salary):
        """Setter для зарплаты.  Выполняет валидацию входных данных."""
        if not isinstance(new_salary, (int, float)):
            raise ValueError("Зарплата должна быть числом.")
        if new_salary < 0:
            raise ValueError("Зарплата не может быть отрицательной.")
        print("Установка новой зарплаты...")
        self._salary = new_salary
    @property
    def name(self):
        return self._name
    @name.setter
    def name(self, new_name):
        if not isinstance(new_name, str):
            raise ValueError("Имя должно быть строкой")
        self._name = new_name
    @salary.deleter
    def salary(self):
        """Deleter для зарплаты (обычно не используется, но возможен)."""
        print("Удаление информации о зарплате (не рекомендуется).")
        del self._salary
  emp = Employee("Alice", 50000)
  print(emp.salary)  # Использует геттер salary
  emp.salary = 60000  # Использует сеттер salary
  print(emp.salary)
  del emp.salary # Использование deleter
  #print(emp.salary) # Вызовет AttributeError, так как self._salary удален
  Методы:
Методы также играют важную роль в контроле доступа.  Приватные методы (начинающиеся с двойного подчеркивания, например __private_method) предназначены для внутреннего использования внутри класса и не должны вызываться напрямую извне.  Хотя Python не обеспечивает абсолютной приватности, такое соглашение подразумевает, что эти методы являются деталями реализации и могут быть изменены без предупреждения.
Пример:
class BankAccount:
    def __init__(self, account_number, balance):
        self._account_number = account_number # protected
        self._balance = balance # protected
    def deposit(self, amount):
        """Публичный метод для пополнения счета."""
        if amount <= 0:
            raise ValueError("Сумма пополнения должна быть положительной.")
        self._balance += amount
        self.__log_transaction(f"Пополнение: +{amount}") # Вызов приватного метода
    def withdraw(self, amount):
        """Публичный метод для снятия средств."""
        if amount <= 0:
            raise ValueError("Сумма снятия должна быть положительной.")
        if amount > self._balance:
            raise ValueError("Недостаточно средств на счете.")
        self._balance -= amount
        self.__log_transaction(f"Снятие: -{amount}") # Вызов приватного метода
    def get_balance(self):
        return self._balance
    def __log_transaction(self, transaction):
        """Приватный метод для записи транзакций (внутренняя логика)."""
        print(f"Лог транзакции: {transaction}")
  account = BankAccount("12345", 1000)
  account.deposit(500)
  account.withdraw(200)
  print(f"Баланс: {account.get_balance()}")
  #account.__log_transaction("Попытка прямого вызова!") #  Не рекомендуется и может привести к неожиданному поведению.
  Защищенные атрибуты и методы:
Атрибуты и методы, начинающиеся с одного подчеркивания (например, _protected_attribute), являются "защищенными".  Это соглашение подразумевает, что они предназначены для использования внутри класса и его подклассов, но не должны использоваться напрямую извне. Python не применяет это ограничение, но это помогает поддерживать чистоту кода и избегать случайных изменений внутренней структуры класса.
В заключение:
Использование свойств и методов, особенно приватных и защищенных, является важной частью объектно-ориентированного программирования на Python. Они позволяют контролировать доступ к данным класса, выполнять валидацию, добавлять логику и скрывать детали реализации, что повышает безопасность и упрощает поддержку кода.