Вопрос-Ответ

What is the meaning of single and double underscore before an object name?

Что означают одинарные и двойные подчеркивания перед именем объекта?

Что означают одинарные и двойные начальные подчеркивания перед именем объекта в Python?

Переведено автоматически
Ответ 1

Одинарное подчеркивание

В классах имена с начальным подчеркиванием указывают другим программистам, что атрибут или метод предназначен для использования внутри этого класса. Однако конфиденциальность никоим образом не обеспечивается. Использование передних символов подчеркивания для функций в модуле указывает на то, что его не следует импортировать откуда-либо еще.

Из руководства по стилю PEP-8:


_single_leading_underscore: слабый индикатор "внутреннего использования". Например. from M import * не импортирует объекты, имя которых начинается с подчеркивания.


Двойное подчеркивание (искажение имени)

Из документации по Python:


Любой идентификатор вида __spam (по крайней мере, два начальных подчеркивания, не более одного завершающего подчеркивания) текстуально заменяется на _classname__spam, где classname - текущее имя класса с удаленными начальными подчеркиваниями. Это искажение выполняется без учета синтаксической позиции идентификатора, поэтому его можно использовать для определения частного экземпляра класса и переменных класса, методов, переменных, хранящихся в глобальных файлах, и даже переменных, хранящихся в экземплярах. закрыто для этого класса в экземплярах других классов.


И предупреждение с той же страницы:


Искажение имен предназначено для того, чтобы предоставить классам простой способ определять “частные” переменные и методы экземпляра, не беспокоясь о переменных экземпляра, определенных производными классами, или манипулируя переменными экземпляра кодом вне класса. Обратите внимание, что правила искажения разработаны в основном для предотвращения несчастных случаев; для определенного пользователя все еще возможно получить доступ к переменной, которая считается частной, или изменить ее.


Пример

>>> class MyClass():
... def __init__(self):
... self.__superprivate = "Hello"
... self._semiprivate = ", world!"
...
>>> mc = MyClass()
>>> print mc.__superprivate
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: myClass instance has no attribute '__superprivate'
>>> print mc._semiprivate
, world!
>>> print mc.__dict__
{'_MyClass__superprivate': 'Hello', '_semiprivate': ', world!'}
Ответ 2

  • _foo: Всего лишь соглашение. Способ для программиста указать, что переменная является частной (что бы это ни означало в Python).



  • __foo: Это имеет реальное значение. Интерпретатор заменяет это имя на _classname__foo, чтобы гарантировать, что имя не будет перекрываться с аналогичным именем в другом классе.



  • __foo__: Всего лишь соглашение. Способ использования системой Python имен, которые не будут конфликтовать с именами пользователей.



Никакие другие формы подчеркивания не имеют значения в мире Python. Кроме того, в этих соглашениях нет разницы между классом, переменной, глобальным и т.д.

Ответ 3

Пока отличные ответы, но не хватает некоторых лакомых кусочков. Одинарное подчеркивание в начале - это не совсем просто соглашение: если вы используете from foobar import *, а модуль foobar не определяет __all__ список, имена, импортированные из модуля, не включают имена с начальным подчеркиванием. Допустим, это в основном условно, поскольку в данном случае это довольно неясный угол;-).

Соглашение о подчеркивании перед началом широко используется не только для частных имен, но и для того, что C ++ назвал бы защищенными - например, имена методов, которые полностью предназначены для переопределения подклассами (даже те, которые должны быть переопределены, поскольку в базовом классе они raise NotImplementedError!-) часто являются именами, начинающимися с одинарного подчеркивания, чтобы указать коду, использующему экземпляры этого класса (или подклассов), что указанные методы не предназначены для прямого вызова.

Например, чтобы создать потокобезопасную очередь с другой дисциплиной обслуживания, отличной от FIFO, нужно импортировать Queue, subclasses Queue .Очередь и переопределяет такие методы, как _get и _put; "клиентский код" никогда не вызывает эти методы ("hook"), а скорее ("организующие") общедоступные методы, такие как put и get (это известно как шаблон проектирования шаблонного метода - смотрите, например, Здесь интересную презентацию, основанную на видеозаписи моего выступления на эту тему, с добавлением кратких описаний стенограммы).

Редактировать: Ссылки на видео в описании выступлений теперь разорваны. Вы можете найти первые два видео здесь и здесь.

Ответ 4

._variable является полуприватным и предназначен только для условностей

.__variable часто ошибочно считается сверхпринадлежным, в то время как на самом деле это означает просто использовать namemangle для предотвращения случайного доступа[1]

.__variable__ обычно зарезервировано для встроенных методов или переменных

Вы все равно можете получить доступ к .__mangled переменным, если вам этого отчаянно хочется. Двойное подчеркивание просто изменяет название или переименовывает переменную во что-то вроде instance._className__mangled

Пример:

class Test(object):
def __init__(self):
self.__a = 'a'
self._b = 'b'

>>> t = Test()
>>> t._b
'b'

t._b доступен, потому что он скрыт только по соглашению

>>> t.__a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute '__a'

t.__a не найден, потому что он больше не существует из-за изменения имени

>>> t._Test__a
'a'

Используя instance._className__variable вместо просто имени с двойным подчеркиванием, вы можете получить доступ к скрытому значению

python