_attribute), сигнализируют, что это внутренние детали, и их не следует использовать напрямую вне класса.__attribute), подвергаются "name mangling". Python изменяет имя, затрудняя доступ к ним напрямую извне.@property, @attribute.setter), позволяющие валидировать значения и выполнять другие действия при чтении и записи.Важно понимать, что это соглашения, а не строгая защита. Можно обойти эти механизмы, но это считается плохой практикой.
Инкапсуляция в Python не является строгой в том смысле, что нельзя сделать атрибут или метод абсолютно недоступным извне класса. Однако, Python предоставляет соглашения и техники для имитации и поощрения безопасного изменения атрибутов и методов. Эти техники помогают предотвратить случайные или злонамеренные изменения внутреннего состояния объекта, обеспечивая контролируемый доступ и логику модификации.
    1. Использование одинарного подчеркивания (_) для обозначения "защищенных" атрибутов и методов:
  
    Атрибут или метод, имя которого начинается с одинарного подчеркивания (например, _attribute или _method()), считается "защищенным".  Это соглашение указывает на то, что этот атрибут/метод предназначен для внутреннего использования внутри класса и его подклассов.  Хотя к нему можно получить доступ извне класса, это считается плохой практикой и нарушением принципов инкапсуляции.  Разработчик должен понимать, что он вмешивается во внутреннюю реализацию класса, и делать это только с крайней необходимостью и полным пониманием последствий.
  
class MyClass:
    def __init__(self):
        self._protected_attribute = 10
    def _protected_method(self):
        print("Это защищенный метод")
obj = MyClass()
print(obj._protected_attribute)  # Можно получить доступ, но не рекомендуется
obj._protected_method()          # Можно вызвать, но не рекомендуется
  
    2. Использование двойного подчеркивания (__) для обозначения "приватных" атрибутов и методов (name mangling):
  
    Атрибут или метод, имя которого начинается с двойного подчеркивания (например, __attribute или __method()), подвергается "name mangling".  Это означает, что интерпретатор Python изменяет имя атрибута/метода, добавляя к нему имя класса.  Например, __attribute в классе MyClass становится _MyClass__attribute.  Это затрудняет доступ к атрибуту/методу извне класса, но не делает его невозможным.  Основная цель name mangling – избежать конфликтов имен атрибутов/методов в подклассах.
  
class MyClass:
    def __init__(self):
        self.__private_attribute = 20
    def __private_method(self):
        print("Это приватный метод")
obj = MyClass()
# print(obj.__private_attribute)  # AttributeError: 'MyClass' object has no attribute '__private_attribute'
print(obj._MyClass__private_attribute) # Доступ через name mangling, но крайне не рекомендуется
obj._MyClass__private_method()           # Вызов через name mangling, но крайне не рекомендуется
  3. Использование свойств (properties) для контролируемого доступа к атрибутам:
    Свойства предоставляют способ определения методов-геттеров (getter), сеттеров (setter) и делиторов (deleter) для атрибутов.  Это позволяет реализовать логику проверки и преобразования данных при чтении и записи атрибутов, а также предотвратить прямой доступ к ним.  Свойства – это мощный механизм для инкапсуляции и обеспечения контролируемого доступа к внутреннему состоянию объекта.
  
class MyClass:
    def __init__(self):
        self._value = 0  # Используем защищенный атрибут для хранения значения
    @property
    def value(self):
        """Получить значение атрибута value."""
        return self._value
    @value.setter
    def value(self, new_value):
        """Установить значение атрибута value с проверкой."""
        if new_value < 0:
            raise ValueError("Значение не может быть отрицательным")
        self._value = new_value
    @value.deleter
    def value(self):
        """Удалить атрибут value (если это имеет смысл)."""
        del self._value
obj = MyClass()
print(obj.value)  # Используем геттер (property)
obj.value = 5    # Используем сеттер (property)
# obj.value = -1  # Вызовет ValueError
del obj.value    # Используем делитор (property)
  Резюме:
Инкапсуляция в Python реализуется в основном за счет соглашений и использования свойств. Одинарное и двойное подчеркивание являются индикаторами для разработчиков, что к атрибуту или методу следует относиться с осторожностью. Свойства предоставляют самый надежный способ контролировать доступ к атрибутам и обеспечивать целостность данных. Важно помнить, что в Python нет "абсолютной" приватности, но эти механизмы позволяют эффективно управлять доступом и защищать внутреннее состояние объектов. Выбор подходящей техники зависит от конкретной ситуации и требований к безопасности и гибкости.