Этот вопрос проверяет понимание соглашений о "защищённых" и внутренних именах в Python и того, как ведущий одинарный подчёркивания влияет на использование и читабельность кода.
Имена, начинающиеся с одного подчёркивания (_name), по соглашению считаются "внутренними" и не предназначены для прямого использования извне модуля или класса. Внутри классов такой префикс обычно означает "protected" атрибут, который не стоит трогать снаружи, хотя технически доступ к нему не запрещён. На уровне модуля имена с _ не импортируются при from module import *. Сам интерпретатор не делает из такого имени "секрет", это лишь слабая защита и подсказка программистам. Основная идея — явно отделить публичное API от внутренней реализации.
Определение:_name — это соглашение об "внутреннем" или "защищённом" имени, которое не входит в публичный интерфейс и не предназначено для прямого использования внешним кодом.
Важно понимать, что одинарное подчёркивание — это именно соглашение, а не механизм жёсткой защиты, как, например, private в других языках.
В модулях одинарное подчёркивание используется для обозначения "неэкспортируемых" имён.
Имена вида _helper_function, _INTERNAL_CONSTANT:
Считаются деталями реализации.
Не должны использоваться внешним кодом как часть публичного API.
При выполнении from module import *:
Имена, начинающиеся с _, игнорируются (если не определён __all__).
Python
# module helpers.py
_internal_cache = {}
def _normalize_name(name: str) -> str:
return name.strip().lower()
def public_api(name: str) -> str:
return _normalize_name(name)
# при from helpers import * в пространство имён попадёт только public_api
Внутри классов _attr обычно значит "не трогать снаружи без необходимости":
_balance, _connection, _logger:
Предназначены для внутреннего использования внутри класса и его потомков.
Используются как предупреждение другим разработчикам: изменение таких атрибутов может сломать инварианты объекта.
Python
class BankAccount:
def __init__(self, initial: int):
self._balance = initial # "protected" – внутренний атрибут
def deposit(self, amount: int) -> None:
self._balance += amount
def get_balance(self) -> int:
return self._balance
Внешний код может обратиться к account._balance, но это считается плохим стилем, потому что обходит публичный интерфейс.
_ как специальное имяЕсть ещё пару практик, связанных с одним подчёркиванием:
В REPL _ часто хранит результат последнего выражения.
В циклах _ используют как имя для "неиспользуемой" переменной:
Python
for _ in range(3):
print("Hello") # переменная цикла не используется
Это не "защита", а просто соглашение: так явно видно, что значение не важно.
Использовать одинарный _ в начале имени стоит, когда:
Вы хотите отделить публичный интерфейс (API) от внутренней реализации модуля или класса.
Вы хотите предупредить других разработчиков: "не полагайтесь на это, это может измениться".
Вам нужно скрыть вспомогательные функции/переменные при from module import *.
Одинарное подчёркивание в начале имени — это способ сообщить другим разработчикам и инструментам, что это внутренний элемент. Он не делает имя приватным, но помогает отделить стабильное публичное API от деталей реализации и улучшает структуру кода.