Символ нижнего подчеркивания

Символу нижнего подчеркивания (_) в Python присущ ряд особенностей.

В большинстве языков программирования (хотя, конечно же не во всех) этот символ используется в названиях функций и переменных, но в Python он имеет особое значение. Если вы Python-программист, то вероятно знакомы с таким синтаксисом: for _ in range(10) , __init__(self).

Этот пост посвящен объяснению того, как использовать нижнее подчеркивание (_) и как его понимать в различных контекстах.

Известно пять случаев с использования нижнего подчеркивания в Python.

  1. Для хранения значения последнего выражения в интерпретаторе.
  2. Для игнорирования конкретного значения (так сказать «Мне без разницы»).
  3. Для придания специального значения переменным и функциям при наименовании.
  4. Для использования функций «Internationalization(i18n)» или «Localization(l10n)».
  5. Для разделения цифр в числе или символов в литерале.

Давайте посмотрим каждый из перечисленных случаев.

Случай использования в интерпретаторе

Интерпретатор Python’а хранит последнее значение в специальной переменной с именем «_». Эта особенность используется в первую очередь в стандартном интерпретаторе CPython, как, впрочем, и в других интерпретаторах Python.

 >>> 10 
10 
>>> _ 
10 
>>> _ * 3 
30 
>>> _ * 20 
600

Случай игнорирования значений

Нижнее подчеркивание также используется для игнорирования конкретных значений. Если конкретное значение не нужно или значения нигде не используются, просто присвойте их нижнему подчеркиванию.

# Ignore a value when unpacking
x, _, y = (1, 2, 3) # x = 1, y = 3 
# Ignore the multiple values. It is called "Extended Unpacking" which is available in only Python 3.x
x, *_, y = (1, 2, 3, 4, 5) # x = 1, y = 5  
# Ignore the index
for _ in range(10):     
    do_something()  
# Ignore a value of specific location
for _, val in list_of_tuple:
    do_something()

Случай придания специфических значений именам переменных и функций

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

_single_leading_underscore

Это соглашение используется для объявления приватных переменных, функций, методов и классов в модуле. При этом все, что связано с этим соглашением, игнорируется в from module import *.

Хотя, конечно же, Python не поддерживает истинной приватности, поэтому можно непосредственно вызывать их из других модулей. Поэтому иногда это называют «нестрогий указатель внутреннего использования«.

_internal_name = 'one_nodule' # private variable
_internal_version = '1.0' # private variable

class _Base: # private class
    _hidden_factor = 2 # private variable
    def __init__(self, price):
        self._price = price
    def _double_price(self): # private method
        return self._price * self._hidden_factor
    def get_double_price(self):
        return self._double_price() 

single_trailing_underscore_

Это соглашение предотвращает конфликты между ключевыми или стандартными словами.

Tkinter.Toplevel(master, class_='ClassName') # Avoid conflict with 'class' keyword
list_ = List.objects.get(1) # Avoid conflict with 'list' built-in type

__double_leading_underscore

В этом случае речь идет о синтаксисе, а не о соглашении. Двойное нижнее подчеркивание искажает имена атрибутов класса и исключает конфликты между именами атрибутов классов. (Так называемое «декорирование», означающее, что компилятор или интерпретатор изменяет имена переменных или функций по некоторым правилам). Правило декорирования в Python добавляется «_ИмяКласса» перед именами атрибутов, объявленных с двойным нижним подчеркиванием.

То есть, если написать метод с именем «__метод» в классе, имя будет декорировано следующим образом: «_ИмяКласса__метод».

 class A:
    def _single_method(self):
        pass
    def __double_method(self): # for mangling
        pass
class B(A):
    def __double_method(self): # for mangling
        pass

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

__double_leading_and_trailing_underscore__

Это соглашение используется для специальных переменных или методов (так называемый «магический метод») таких как __init____len__. Эти методы определяют особые синтаксические признаки или выполняют специфические действия. Например, __file__ указывает местоположение Python-файла, __eq__ выполняется, когда истинно условие a == b.

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

 class A:
    def __init__(self, a): # use special method '__init__' for initializing
        self.a = a
    def __custom__(self): # custom special method. you might almost do not use it
        pass

Случай использования функций Internationalization(i18n) или «Localization(l10n)

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

Встроенная библиотека gettext, а также фреймворк Django также поддерживают и используют это соглашение.

# see official docs : https://docs.python.org/3/library/gettext.html
import gettext
gettext.bindtextdomain('myapplication','/path/to/my/language/directory')
gettext.textdomain('myapplication')
_ = gettext.gettext
# ...
print(_('This is a translatable string.'))

Случай разделения чисел в числе или символов в литерале

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

dec_base = 1_000_000
bin_base = 0b_1111_0000
hex_base = 0x_1234_abcd
print(dec_base) # 1000000
print(bin_base) # 240
print(hex_base) # 305441741

Заключение

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

Надеюсь, что вы, как и я, нашли для себя много полезного при чтении моего поста. Спасибо!

Перевод статьи mingrammer: Understanding the underscore( _ ) of Python

Предыдущая статьяВведение в веб-скрэпинг с помощью Node.js
Следующая статьяМагическая формула для улучшения навыков программирования