April 21, 2024

Подчеркивания в именах Python. Коротко о главном

Без особых углублений в детали давайте разберем главные нюансы в применении подчеркиваний в именах Python. Рассмотрим все часто используемые варианты.

Более детально некоторые аспекты буду освещать в будущих статьях.

Приступим!

1. Игнорирование значений


Игнорирование одного значения

Часто можно встретить запись подобного вида:

for _ in range(2):
    print("Make repeated action")

> Make repeated action
> Make repeated action

или такого:

scheme, _, path = ("https", "t.me", "/python3_with_love")
print(scheme, path, sep="\\n")

> https
> /python3_with_love

В этом случае одно подчеркивание позволяет нам опустить использование имени, когда оно попросту ненужно. По сути, мы просто присваиваем значение символу нижнего подчеркивания и дальше в коде его не используем.

Игнорирование нескольких значений

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

first, *_, last = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
print(first, last, sep="\\n")

> 1
> 10

Можем просто перечислить несколько подчеркиваний для игнорирования значений:

scheme, _, _ = ("https", "t.me", "/python3_with_love")
print(scheme)

> https

2. Подчеркивания перед именем


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

Одно подчеркивание перед именем указывает на то, что объект предназначен для внутреннего использования и вызывать его вне обозначенного класса, модуля или функции не стоит. Можно назвать это псевдо-приватной переменной или методом. “Псевдо” именно потому, что объект возможно вызывать извне, но делать это строго не рекомендуется.

Рассмотрим пример:

class ExampleClass:
    _pseudo_private_var = 1
    public_var = 2

a = ExampleClass.public_var
b = ExampleClass._pseudo_private_var
print(a, b)

> 2 1

Нам удалось получить доступ к обеим переменным, все значения распечатались без ошибок. Но об использовании приватных объектов нам напомнит IDE:

Кроме того, приватную переменную не подсветит и автокомплит - когда мы напишем ExampleClass.,в предложенных вариантах мы не увидим нашу приватную переменную.

Для усложнения доступа к приватной переменной нам приходят на помощь 2 нижних подчеркивания.

Два подчеркивания перед именем. Искажения имен

Рассмотрим тот же пример, только добавим еще одну переменную с 2 подчеркиваниями перед именем:

class ExampleClass:
    __private_var = 0
    _pseudo_private_var = 1
    public_var = 2

c = ExampleClass.__private_var

> AttributeError: type object 'ExampleClass' has no attribute '__private_var'

Вот, другое дело! Теперь вместо доступа к переменной мы получили исключение AttributeError .

Выглядит действительно как приватный атрибут, но есть 1 нюанс: когда мы указываем 2 подчеркивания перед именем объекта, то используется искажение имен атрибутов класса.

Давайте воспользуемся встроенной функцией dir() и посмотрим все атрибуты нашего класса:

print(dir(ExampleClass))

> ['_ExampleClass__private_var', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_pseudo_private_var', 'public_var']

Из списка всех атрибутов, найдем созданные нами: _ExampleClass__private_var, _pseudo_private_var, public_var .

Наша приватная переменная теперь с новым именем и именно поэтому мы уже не можем ее вызвать классическим способом ExampleClass.__private_var .

НО! Все-таки получить значение этой переменной мы можем, если укажем искаженное имя при вызове:

print(ExampleClass._ExampleClass__private_var)

> 0

Пусть возможность есть, но делать так не надо. :)

3. Подчеркивания после имени


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

Одно подчеркивание после имени следует использовать, когда указанные нами имена совпадают со встроенными, например: type(), id(), object(), …

Вместо подобной записи:

def _some_func(object, type):
    return object, type

Следует использовать запись следующего вида:

def _some_func(object_, type_):
    return object_, type_

И никто к вам не придерется.

4. Двойные подчеркивания до и после имени


Таким образом обозначаются специальные переменные и методы.

Пара примеров использования переменных:

print(__file__)
print(__name__)

> /Users/me/sources/file_for_test.py
> __main__

Специальные методы еще называются магическими (в оригинале - dunder methods) - это отдельный вид искусства в Python.

Примерами таких методов выступают __init__, __str__, __repr__ и так далее, их довольно много. Сейчас их разбирать не будем, это целая отдельная тема.

5. Разделение чисел и вывод последнего значения в интерпретаторе


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

Разделение чисел с помощью подчеркивания

Для удобства чтения числа можно разделять подчеркиванием:

num_1 = 1_000_000_000
num_2 = 1000000000

assert num_1 == num_2

С помощью проверки на равенство значений мы убедились, что num_1 равен num_2, разница лишь в читаемости.

Вывод последнего значения в интерпретаторе

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

> python
>>> 10 ** 2
100
>>> _
100
>>> exit()

Теперь вы знаете, зачем нужны все эти подчеркивания и для чего их применять. Осталось только практиковать.