Подчеркивание в Python: 5 ключевых способов использования символа _
Для кого эта статья:
- Начинающие и средние Python-разработчики, желающие улучшить свои навыки кодирования.
- Профессионалы, стремящиеся к написанию читаемого и поддерживаемого кода на Python.
Люди, интересующиеся лучшими практиками программирования и стандартами PEP8.
Одиночное подчеркивание в Python — тот ненавязчивый символ, который может рассказать о коде больше, чем иные многострочные комментарии. Когда я впервые увидел код с переменной "temp" или метод "get_data()", я решил, что это просто странный стиль именования. Ошибка, которую совершают многие. Подчеркивание в Python — это тихий разговор между разработчиками, своеобразный шифр, определяющий границы доступа, временные конструкции и даже намекающий на интернационализацию. Сегодня разберём пять ключевых применений этого скромного символа, который может радикально изменить восприятие вашего кода. 🐍
Если вы хотите не просто понимать символы в Python, а писать эффективный и профессиональный код, вам пригодится Обучение Python-разработке от Skypro. Программа включает не только базовые синтаксические конструкции, но и лучшие практики структурирования кода, включая правильное использование подчеркивания согласно PEP8. Вы научитесь писать код, который будет понятен не только вам, но и любому другому Python-разработчику.
Одиночное подчеркивание в Python: для чего используется
Символ одиночного подчеркивания (_) в Python — это не просто стилистическое украшение, а мощный инструмент коммуникации между разработчиками. Вопреки распространенному мнению, Python не имеет жесткой концепции приватности переменных, как, например, Java или C++. Вместо этого, он использует "соглашения", основанные на символах подчеркивания. 📝
Основные случаи использования одиночного подчеркивания можно разделить на пять категорий:
- Обозначение "внутренних" или "приватных" переменных/методов
- Использование в качестве временной или неважной переменной
- Доступ к результату последнего выражения в интерпретаторе
- Разделение цифр в числовых литералах для улучшения читаемости
- Применение в интернационализации для пометки строк для перевода
Рассмотрим каждое применение подробнее и с примерами кода.
Александр Петров, Senior Python Developer
Когда я только начинал работать с большими проектами на Python, меня постоянно смущало обилие переменных с подчеркиваниями. В одном крупном проекте мой код постоянно отклоняли на код-ревью из-за неправильного использования подчеркиваний. Тогда я составил для себя шпаргалку по всем вариантам использования этого символа. Через пару недель я уже автоматически применял правильные соглашения, а мой код стал намного понятнее для команды. Эта маленькая деталь существенно ускорила мою интеграцию в проект.
Для наглядности сравним различные типы подчеркиваний в Python и их значение:
| Тип подчеркивания | Пример | Значение |
|---|---|---|
| Одиночное в начале | _variable | Соглашение: "внутренняя" переменная |
| Одиночное отдельно | for _ in range(5) | Временная/неиспользуемая переменная |
| Одиночное в интерпреторе | >>>> 2 + 2<br>>>> _ | Результат последнего выражения |
| Разделитель в числах | 1_000_000 | Улучшение читаемости чисел |
| В функции gettext | _('Hello') | Пометка для интернационализации |
Важно отметить, что это именно соглашения, а не строгие правила языка. Python не будет блокировать доступ к переменным с подчеркиванием — это вопрос профессиональной этики разработчиков, которые договорились об определенных правилах взаимодействия с кодом.

Соглашение о переменных в PEP8: роль подчеркивания
PEP8 — это руководство по стилю кода в Python, которое устанавливает соглашения для написания читаемого и поддерживаемого кода. В контексте подчеркивания, PEP8 предоставляет четкие рекомендации, которые стали стандартом в сообществе разработчиков. 🔍
Согласно PEP8, одиночное подчеркивание в начале имени указывает, что переменная или метод предназначены для внутреннего использования. Это сигнализирует другим разработчикам: "этот элемент не является частью публичного API модуля, он может измениться без предупреждения".
def calculate_total(items):
# Публичный метод
return _calculate_subtotal(items) + _calculate_tax(items)
def _calculate_subtotal(items):
# Внутренний вспомогательный метод
return sum(item.price for item in items)
def _calculate_tax(items):
# Еще один внутренний метод
return sum(item.price * item.tax_rate for item in items)
В этом примере только calculate_total предназначен для вызова извне, в то время как _calculate_subtotal и _calculate_tax — это внутренние детали реализации, которые могут быть изменены без нарушения интерфейса модуля.
Еще один аспект, который описывает PEP8, — это использование одиночного подчеркивания для избежания конфликтов с ключевыми словами Python:
class_ = "Python 101" # Избегаем конфликта с ключевым словом "class"
from_ = "New York" # Избегаем конфликта с ключевым словом "from"
PEP8 также рекомендует использовать одиночное подчеркивание в качестве временной переменной, когда значение не будет использоваться:
# Нам не нужны сами элементы, только их количество
for _ in range(5):
print("Hello")
# Распаковка кортежа, где нас интересует только второй элемент
_, value = get_data()
| Соглашение в PEP8 | Применение | Эффект на импорт |
|---|---|---|
| Одиночное подчеркивание в начале | _private_var = 10 | Не импортируется при from module import * |
| Без подчеркивания | public_var = 10 | Импортируется при from module import * |
| Двойное подчеркивание в начале | __mangled_var = 10 | Подвергается "name mangling", не импортируется |
| Подчеркивание после имени | class_ = "Python" | Обычная переменная, импортируется |
| Двойное подчеркивание с обеих сторон | __special_method__ | Специальный метод, импортируется |
Интересно, что модуль __pycache__ содержит двойные подчеркивания с обеих сторон, сигнализируя о том, что это специальный модуль Python, а не что-то, что должно импортироваться или использоваться напрямую.
Временные переменные с подчеркиванием: улучшаем код
Использование одиночного подчеркивания для временных переменных — элегантный способ показать, что значение переменной не имеет значения в контексте выполнения. Этот паттерн не только делает код более читаемым, но и может предотвратить ошибки, связанные с неправильным использованием таких переменных. 🔄
Самый распространенный случай — использование подчеркивания в циклах, когда нам важен сам факт повторения, а не итерационная переменная:
# Повторяем действие 5 раз без использования переменной цикла
for _ in range(5):
print("Это повторяется 5 раз")
# Вместо
for i in range(5):
print("Это повторяется 5 раз") # i не используется
Второй распространенный случай — распаковка кортежей или списков, когда нас интересуют только определенные элементы:
# Нам нужен только второй элемент
_, important_data, _ = function_returning_three_values()
# Лучше, чем
data1, important_data, data3 = function_returning_three_values()
# data1 и data3 не используются
Этот подход особенно полезен при работе с функциями, возвращающими несколько значений, или при обработке данных из внешних источников:
# При обработке CSV файла, где нужны только определенные колонки
for row in csv_reader:
id_, name, _, _, email = row # Пропускаем ненужные поля
process_user(id_, name, email)
Марина Ковалева, Python Tech Lead
Я руководила проектом, где было много аналитического кода с обработкой больших многомерных данных. Код был сложным для понимания, с множеством переменных, назначение которых было неясно. Когда новый разработчик присоединился к команде, он начал систематически переименовывать неиспользуемые переменные в "_". Результат был поразительным — код стал значительно понятнее, потому что мы могли сразу видеть, какие данные действительно важны, а какие просто проходят через цепочку обработки. Это простое изменение сократило время на ознакомление с кодом для новых сотрудников с недели до пары дней.
Важное замечание: хотя символ подчеркивания является общепринятым обозначением для временных переменных, Python всё равно присваивает значение этой переменной. Это значит, что вы можете случайно использовать это значение в дальнейшем коде, что приведет к неожиданному поведению:
for _ in range(5):
pass
print(_) # Выведет 4, последнее значение из range(5)
Поэтому важно быть внимательным и не использовать подчеркивание как обычную переменную в том же контексте.
Еще одно интересное применение — использование подчеркивания в интерактивном интерпретаторе Python для доступа к результату последнего выражения:
>>> 2 + 3
5
>>> _ * 2
10
>>> _ + 5
15
Это удобно для последовательных вычислений без необходимости сохранять промежуточные результаты в именованных переменных.
Синтаксис подчеркивания для приватных атрибутов
В отличие от многих объектно-ориентированных языков, Python не имеет явного механизма приватности. Вместо ключевых слов вроде private или protected, Python использует соглашения на основе подчеркиваний. Однако эти соглашения имеют разную степень "жесткости". 🔒
Одиночное подчеркивание в начале имени атрибута или метода является "мягким" указанием на приватность:
class User:
def __init__(self, name, email):
self.name = name # Публичный атрибут
self._email = email # "Приватный" атрибут
def get_info(self): # Публичный метод
return self.name
def _update_email(self, new_email): # "Приватный" метод
self._email = new_email
В этом примере _email и _update_email отмечены как внутренние детали реализации, которые не должны использоваться напрямую. Однако технически ничто не мешает получить к ним доступ извне:
user = User("John", "john@example.com")
print(user._email) # Технически работает, но нарушает соглашение
user._update_email("newemail@example.com") # То же самое
Важный эффект одиночного подчеркивания — такие имена не импортируются при использовании конструкции from module import *:
# В module.py
public_var = 1
_private_var = 2
# В другом файле
from module import *
print(public_var) # Работает
print(_private_var) # NameError: name '_private_var' is not defined
Это помогает избежать "загрязнения" пространства имен при импорте.
Если вам нужна более строгая форма приватности, Python предлагает двойное подчеркивание:
class Account:
def __init__(self, user_id, balance):
self.user_id = user_id
self.__balance = balance # Имя будет "искажено"
def deposit(self, amount):
self.__balance += amount
def withdraw(self, amount):
if amount <= self.__balance:
self.__balance -= amount
return True
return False
Здесь происходит интересная вещь: Python автоматически переименовывает атрибуты с двойным подчеркиванием, добавляя к ним имя класса. Этот процесс называется "name mangling" (искажение имен):
account = Account("123", 1000)
print(account.user_id) # Работает
print(account.__balance) # AttributeError: 'Account' object has no attribute '__balance'
print(account._Account__balance) # Работает: 1000
Таким образом, двойное подчеркивание обеспечивает некоторую защиту от случайного переопределения в подклассах:
class ChildAccount(Account):
def __init__(self, user_id, balance, parent):
super().__init__(user_id, balance)
self.parent = parent
self.__balance = 0 # Это НЕ переопределит __balance родителя!
В данном случае, self.__balance в ChildAccount будет преобразовано в self._ChildAccount__balance, а не в self._Account__balance, так что оригинальный атрибут родителя останется нетронутым.
Сравнение различных подходов к приватности в Python:
| Подход | Синтаксис | Уровень защиты | Использование |
|---|---|---|---|
| Публичный | attribute | Нет | Часть API класса |
| "Внутренний" | _attribute | Соглашение | Детали реализации, не импортируются с * |
| "Приватный" | __attribute | Name mangling | Защита от конфликтов в подклассах |
| Специальный | __attribute__ | Нет | Специальные методы Python (dunder) |
Интернационализация и одиночное подчеркивание в Python
Одним из наименее известных, но чрезвычайно полезных применений одиночного подчеркивания в Python является его роль в интернационализации (i18n) и локализации (l10n) приложений. Этот аспект особенно важен для разработчиков, создающих программы с поддержкой нескольких языков. 🌎
В стандартной библиотеке Python есть модуль gettext, который обеспечивает инфраструктуру для перевода текстовых строк в приложении. Ключевой функцией этого модуля является функция gettext, которая обычно связывается с одиночным подчеркиванием:
import gettext
# Настройка локализации
gettext.install('myapp', localedir='locale')
# Теперь _ стал функцией для перевода строк
print(_("Hello, world!")) # Выводится переведенная версия строки
Это соглашение настолько распространено, что многие фреймворки и библиотеки, такие как Django, Flask-Babel и другие, используют его по умолчанию.
Почему именно подчеркивание? Это краткий и ненавязчивый символ, который не нарушает читаемость кода, особенно когда многие строки требуют перевода:
def login_page():
return render_template(
'login.html',
title=_("Login"),
header=_("Welcome back"),
submit_button=_("Sign in"),
register_link=_("Create an account")
)
При разработке многоязычных приложений важно помнить о нескольких особенностях использования подчеркивания для интернационализации:
- Не смешивайте использование
_как функции перевода и как временной переменной в одном контексте - Используйте плюрализацию с
ngettextдля строк, зависящих от числа элементов - Помните о контекстной локализации с помощью
pgettext - Добавляйте комментарии для переводчиков, объясняющие контекст использования строк
Пример более сложного сценария с плюрализацией:
from gettext import ngettext
def show_results(count):
message = ngettext(
"Found {count} result",
"Found {count} results",
count
).format(count=count)
return message
print(show_results(1)) # Found 1 result
print(show_results(5)) # Found 5 results
Важно понимать, что когда _ используется для интернационализации, вы не должны использовать его как временную переменную в том же модуле:
# Этот код вызовет ошибку, так как _ теперь функция
import gettext
gettext.install('myapp')
for _ in range(5): # TypeError: 'function' object is not iterable
print(_("Hello"))
Чтобы избежать подобных конфликтов, можно использовать альтернативное имя для функции перевода:
import gettext
translation = gettext.translation('myapp', localedir='locale')
t = translation.gettext
# Теперь можно использовать t для перевода и _ как временную переменную
for _ in range(3):
print(t("Hello"))
Интернационализация с использованием одиночного подчеркивания — это пример того, как простое соглашение может существенно облегчить разработку сложных многоязычных приложений, делая код более чистым и поддерживаемым.
Использование одиночного подчеркивания в Python — это больше чем синтаксическая особенность. Это отражение философии языка, где читаемость и ясные соглашения ценятся выше жестких ограничений. Правильное применение этого символа в коде делает его более профессиональным и понятным для других разработчиков. Умение различать контексты использования подчеркивания — один из признаков зрелого Python-программиста. Применяйте эти знания сознательно, и ваш код станет не только функциональным, но и элегантным.