Шаг 18.
Python: тонкости программирования. Шаблоны для чистого Python. Подчеркивания, дандеры и другое. Одинарный начальный символ подчеркивания: _var

    На этом шаге мы рассмотрим назначение и особенности его использования.

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

    Префикс, состоящий из символа подчеркивания, подразумевается как подсказка, которая должна сообщить другому программисту, что переменная или метод, начинающиеся с одинарного символа подчеркивания, предназначаются для внутреннего пользования. Эта договоренность определена в PEP8, руководстве по стилю оформления наиболее широко применяемого исходного кода Python.


См. PEP8: "Руководство по стилю оформления исходного кода Python": https://www.python.org/dev/peps/pep-0008/.

    Однако эта договоренность не обеспечивается интерпретатором Python. В Python отсутствует строгое разграничение между "приватными" и "публичными" переменными, как в Java. Добавление одинарного символа подчеркивания перед именем переменной больше похоже на размещение крошечного подстрочного предупреждающего знака, который говорит: "Послушай, эта переменная точно не предназначена быть частью открытого интерфейса этого класса. Оставь-ка ее в покое".

    Взгляните на приведенный ниже пример:

>>> class Test:
	def __init__(self):
		self.foo = 11
		self._bar = 23

    Что случится, если создать экземпляр этого класса и попробовать получить доступ к атрибутам foo и _bar, определенным в его конструкторе __init__()?

    Давайте узнаем:

>>> t = Test()
>>> t.foo
11
>>> t._bar
23

    Как видите, одинарный начальный символ подчеркивания в _bar не помешал нам "залезть" в класс и получить доступ к значению этой переменной.

    Все потому, что в Python префикс, состоящий из одинарного подчеркивания, представляет собой просто согласованную договоренность - по крайней мере в том, что касается имен переменных и методов. Вместе с тем начальные символы подчеркивания влияют на то, как имена импортируются из модулей. Предположим, что у вас есть модуль my_module и в нем есть следующий фрагмент кода:

# my_module.py:
def external_func():
    return 23


def _internal_func():
    return 42

    Так вот, если для импорта всех имен из модуля вы будете использовать подстановочный импорт (wildcard import) (*), то Python не будет импортировать имена с начальным символом подчеркивания (если только в модуле не определен список __all__, который отменяет такое поведение):


См. документацию Python "Импортирование с подстановочным знаком * из пакета": https://docs.python.org/3/tutorial/modules.html#importing-from-a-package.
from my_module import *

print(external_func())   # 23
print(_internal_func())  # NameError: "name '_internal_func' is not defined"
Архив с файлами можно взять здесь.

    К слову сказать, подстановочного импорта следует избегать, поскольку он вносит неясность в то, какие имена присутствуют в пространстве имен.


См. PEP 8 "Импортирование": http://pep8.org/#imports.

    Ради ясности лучше придерживаться обычного импорта. Согласованные правила именования с одинарным подчеркиванием, в отличие от подстановочного импорта, обычный импорт не затрагивает:

import my_module

print(my_module.external_func())  # 23
print(my_module._internal_func()) # 42
Архив с файлами можно взять здесь.

    Понимаем, этот момент может показаться немножко запутанным. Если вы придерживаетесь рекомендаций PEP8 в том, что подстановочного импорта следует избегать, то все, что действительно необходимо запомнить, состоит в следующем:

Одинарные символы подчеркивания являются в Python согласованным правилом именования, 
которое говорит о том, что то или иное имя предназначается для внутреннего использования. 
Это договорное правило обычно интерпретатором Python не обеспечивается и предназначено 
для программиста только в качестве подсказки.

    На следующем шаге мы рассмотрим одинарный замыкающий символ подчеркивания.




Предыдущий шаг Содержание Следующий шаг