Что означает двойное подчеркивание в начале имени метода или атрибута класса в Python?
Что проверяют
Знаете ли вы механизм искажения имён и отличаете ли соглашение об именовании от того, что реально делает интерпретатор. Вопрос быстро показывает, откуда пришёл кандидат: из Python или из языка с модификаторами доступа.
Как отвечать
Два ведущих подчёркивания и не более одного завершающего запускают name mangling: в теле класса имя __data превращается в _ClassName__data. Происходит это на этапе компиляции и только внутри тела класса, включая обращения через self.
class Base:
def __init__(self):
self.__data = 1 # реально создаётся _Base__data
b = Base()
b._Base__data # 1, доступ никуда не делсяСмысл не в сокрытии, а в защите от случайного совпадения имён при наследовании: наследник со своим __data не затрёт поле базового класса. Приватности в языке нет, атрибут остаётся доступен по искажённому имени.
Рядом стоит вспомнить соседние соглашения:
_nameэто просьба не трогать, интерпретатор ничего не меняет;__name__не искажается, это имена протоколов вроде__init__;__nameискажается, но только внутри класса, в обычной функции такое имя ничем не примечательно.
Где спотыкаются
Называют это приватностью как в других языках и обещают защиту, которой нет. Правильная формулировка: механизм против конфликта имён, а не против доступа.
Ломают динамику. Искажение делает компилятор по тексту, поэтому getattr(obj, "__data") вернёт ошибку, в __slots__ имя приходится писать как есть, а обращение к obj.__data из функции вне класса вообще не сработает.
Вешают двойное подчёркивание на всё подряд ради инкапсуляции. Потом атрибут не переопределить в наследнике, не подменить в тесте, и любая отладка превращается в набор искажённых имён. Для внутреннего кода достаточно одного подчёркивания, двойное оправдано в базовых классах библиотек, где наследников пишут чужие люди.