Ответ 1
У Python нет модели конфиденциальности, нет модификаторов доступа, таких как C++, С# или Java. Нет никаких "защищенных" или "частных" атрибутов.
Имена с лидирующим двойным подчеркиванием и отсутствием двойного подчеркивания с двойным контролем искажаются, чтобы защитить их от столкновений, когда они унаследованы. Подклассы могут определять свой собственный __private()
и они не будут мешать одному и тому же имени в родительском классе. Такие имена считаются частными; они все еще доступны извне класса, но гораздо менее вероятны случайное столкновение.
Mangling выполняется путем добавления любого такого имени с дополнительным подчеркиванием и именем класса (независимо от того, как это имя используется или существует), эффективно предоставляя им пространство имен. В классе Parent
любой идентификатор __private
заменяется (во время компиляции) именем _Parent__private
, тогда как в классе Child
идентификатор заменяется на _Child__private
, везде в определении класса.
Будет работать следующее:
class Child(Parent):
def foo(self):
self._protected()
def bar(self):
self._Parent__private()
См. Зарезервированные классы идентификаторов в документации по лексическому анализу:
__*
Классовые имена. Имена этой категории, используемые в контексте определения класса, переписываются для использования искаженной формы, чтобы избежать столкновений имен между "частными" атрибутами базового и производного классов.
и ссылочная документация по именам:
Частное имя: когда идентификатор, который имеет текстовое значение в определении класса, начинается с двух или более символов подчеркивания и не заканчивается двумя или более символами подчеркивания, он считается частным именем этого класса. Частные имена преобразуются в более длинную форму до того, как для них генерируется код. Преобразование вставляет имя класса, с удалением ведущих подчеркиваний и добавлением одного подчеркивания перед именем. Например, идентификатор
__spam
встречающийся в классе с именем Ham, будет преобразован в_Ham__spam
. Это преобразование не зависит от синтаксического контекста, в котором используется идентификатор.
Не используйте имена класса-частного, если вы специально не хотите, чтобы вы говорили разработчикам, которые хотят подклассифицировать ваш класс, что они не могут использовать определенные имена или подвергать риску ваш класс. За пределами опубликованных фреймворков и библиотек для этой функции мало пользы.
В руководстве по стилю Python PEP 8 сказано об управлении частным именем:
Если ваш класс предназначен для подкласса, и у вас есть атрибуты, которые вы не хотите использовать подклассами, подумайте об именах их с двумя ведущими символами подчеркивания и отсутствующими символами подчеркивания. Это вызывает алгоритм управления именами Python, где имя класса искажается именем атрибута. Это помогает избежать конфликтов имен атрибутов, если подклассы непреднамеренно содержат атрибуты с тем же именем.
Примечание 1: Обратите внимание, что только имя простого класса используется в измененном имени, поэтому, если подкласс выбирает одно и то же имя класса и имя атрибута, вы все равно можете получить коллизии имен.
Примечание 2:
__getattr__()
может выполнять определенные функции, такие как отладка и__getattr__()
, менее удобно. Однако алгоритм смены имени хорошо документирован и легко выполняется вручную.Примечание 3: Не все любят манипулирование именами. Постарайтесь сбалансировать необходимость во избежание случайных конфликтов имен с потенциальным использованием передовыми абонентами.