Как в Python принято разграничивать публичные, защищенные и приватные атрибуты класса

«Как в Python принято разграничивать публичные, защищенные и приватные атрибуты класса» — вопрос из категории Безопасность, который задают на 10% собеседований Python Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В Python инкапсуляция и разграничение доступа к атрибутам класса основаны на соглашениях об именовании, а не на строгих механизмах языка, как в Java или C++.

1. Публичные (Public) атрибуты

  • Именование: Без ведущих подчеркиваний (self.name).
  • Назначение: Являются частью публичного API класса. Предназначены для свободного использования извне.

2. Защищенные (Protected) атрибуты

  • Именование: Одно ведущее подчеркивание (self._value).
  • Назначение: Сигнал для других разработчиков, что атрибут является внутренней реализацией класса и не предназначен для прямого доступа извне. Однако технически доступ к нему остается открытым.

3. Приватные (Private) атрибуты

  • Именование: Два ведущих подчеркивания (self.__secret).
  • Назначение: Используются, чтобы избежать случайных конфликтов имен атрибутов в дочерних классах.
  • Механизм: Python автоматически применяет к таким именам искажение (name mangling), преобразуя __secret в _ClassName__secret. Это делает случайное обращение к атрибуту сложнее, но не невозможным.

Пример

class MyClass:
    def __init__(self):
        self.public_var = "Я публичный"
        self._protected_var = "Я защищенный"
        self.__private_var = "Я приватный"

obj = MyClass()

# 1. Доступ к публичному атрибуту (нормальная практика)
print(obj.public_var)

# 2. Доступ к защищенному атрибуту (технически возможно, но не рекомендуется)
print(obj._protected_var)

# 3. Прямой доступ к приватному атрибуту вызовет ошибку
try:
    print(obj.__private_var)
except AttributeError as e:
    print(f"Ошибка: {e}")

# 4. Доступ к приватному атрибуту через искаженное имя (возможно, но не нужно)
print(obj._MyClass__private_var)

Вывод:

Я публичный
Я защищенный
Ошибка: 'MyClass' object has no attribute '__private_var'
Я приватный

Ключевой момент: Эти соглашения — это в первую очередь инструмент для написания чистого и поддерживаемого кода, а не механизм безопасности. Для контроля доступа к данным следует использовать свойства (@property).