Как реализована закрытость данных в Python
Что проверяют
Понимаете ли вы, что в Python нет модификаторов доступа, а есть соглашения и один механизм переименования. Следом обычно просят объяснить, зачем тогда двойное подчёркивание и как правильно закрыть поле от записи.
Как отвечать
Начните с принципа: язык рассчитан на то, что разработчик соглашения уважает, поэтому закрытость здесь договорная. Дальше уровни:
_name: внутренняя деталь реализации. Доступ ничем не ограничен, но линтеры и IDE предупредят, аfrom module import *такие имена не импортирует, если не задан__all__;__name: name mangling. Внутри тела класса компилятор переписывает имя в_ClassName__name. Цель не спрятать данные, а избежать конфликта имён при наследовании: подкласс с таким же атрибутом не затрёт поле родителя;__name__: имена с подчёркиваниями с двух сторон не переписываются, это зарезервированные «магические» методы и атрибуты, свои так называть не нужно;@property: главный инструмент инкапсуляции. Снаружи обычный атрибут, внутри геттер и сеттер с проверкой; без сеттера запись вызоветAttributeError;- неизменяемость:
@dataclass(frozen=True),NamedTuple, а__slots__ограничивает набор атрибутов экземпляра.
Полезно показать, что переименование происходит на этапе компиляции и только для идентификаторов в теле класса. getattr(self, "__x") строкой переписан не будет, а снаружи до поля можно добраться через obj._Example__x. Это доказывает, что __ не защита, а предохранитель.
Хороший довод в пользу подхода Python: публичный атрибут всегда можно превратить в property позже, не ломая вызывающий код, поэтому заранее писать get_x() и set_x() не нужно.
Где спотыкаются
Называют __x приватным полем «как в Java» и утверждают, что снаружи оно недоступно. Интервьюер тут же попросит достать его через _Example__x.
Ставят двойное подчёркивание на всё подряд. В итоге подклассы и тесты добираются до поля только через неудобное переименованное имя, хотя хватило бы одного подчёркивания.
Путают __x с __x__ и не могут объяснить, почему __init__ не превращается в _Example__init__.