Введение
В Python подчеркивания играют важную роль в определении семантики имен переменных, методов и классов. Они помогают программистам явно указывать намерения и избегать конфликтов имен. Понимание различных типов подчеркиваний и их влияния на поведение кода повышает читаемость, поддерживаемость и надежность программ на Python.
В рамках этой статьи мы рассмотрим различные виды подчеркиваний и их значение в языке программирования Python.
Виды подчеркиваний:
- Одинарный начальный символ подчеркивания: "_variable";
- Одинарный замыкающий символ подчеркивания: "variable_";
- Одинарный символ подчеркивания: "_";
- Двойной начальный символ подчеркивания: "__variable";
- Двойной начальный и замыкающий символ подчеркивания: "__variable__".
Одинарный начальный символ подчеркивания: _variable
Префикс, состоящий из символа подчеркивания, служит некой подсказкой для программиста, которая означает, что атрибут или метод предназначен для внутреннего использования. Это всего лишь договоренность между программистами, и интерпретатор Python никак за этим не следит. Поэтому этот символ говорит: "Друг, этот метод не должен использоваться за пределами объекта и поэтому не стоит его беспокоить".
Как видно из примера, одинарный символ подчеркивания не помешал обратиться к атрибуту _with_prefix и получить его значение. Однако, если из первого модуля импортируется все, что в нем есть во второй модуль, то переменные или функции с одним подчеркиванием вначале не будут доступны во втором модуле, исключение вносит переменная __all__.
В module_1.py есть две функции, одна с подчеркиванием вначале, другая нет.
Пример с импортом через *:
Функция _func_with_prefix не была импортирована из-за нижнего подчеркивания вначале, но если импортировать явно, указывая названия объектов, то нижнее подчеркивание вначале никакого эффекта не внесет.
Пример с явным импортом:
Как и говорил ранее, исключение вносит переменная __all__. Если в ней явно указать объекты, которые могут быть импортированы с текущего модуля, то при попытке получить все объекты используя *, мы получим именно те объекты, которые находятся в переменной __all__.
Пример с импортом через * с __all__:
Здорово, не правда ли?!
Одинарный замыкающий символ подчеркивания: "variable_"
Бывает такое, что самое подходящее имя переменной уже занято ключевым словом языка Python, например class и def. Их нельзя использовать в качестве названия переменной и в таком случае можно добавить нижнее подчеркивание в конец имени, чтобы избежать конфликтов из-за совпадении имен:
Замыкающий одинарный символ подчеркивания используется по договоренности, чтобы избежать конфликтов имен из-за совпадения.
Одинарный символ подчеркивания: "_"
Одинарный символ подчеркивания можно использовать в качестве имени переменной, чтобы подчеркнуть, что эта переменная временная или незначительная.
В примере выше представлен цикл, которому не нужен доступ к нарастающему индексу, и в этом случае можно применить _, указывая на то, что эта лишь временная переменная.
При распаковке кортежа, могут понадобиться только отдельные переменные name и city, а возраст и профессия нас не интересуют. В этом случае вместо того, чтобы давать названия им, можно использовать _.
Если работать в сеансе интерпретатора Python, то используя нижнее подчеркивание, получим предыдущий результат.
Двойной начальный символ подчеркивания: "__variable"
Наименования, которые были рассмотрены ранее, имеют свой смысл только по средствам договоренности. В случае атрибутов и методов класса в Python, которые начинаются с двойного символа подчеркивания, работают немного по-другому.
Префикс, состоящий из двойного символа подчеркивания, заставляет интерпретатор Python переписать имя атрибута или метода, для того, чтобы избежать конфликтов из-за совпадения имен. Такое переписывание называется искажением имен (name mangling). Так же использование двойного подчеркивания перед именем атрибута или метода позволяет скрыть их от прямого доступа извне класса. Это помогает предотвратить случайное изменение или использование атрибутов и методов, которые не предназначены для использования вне класса.
Как можно увидеть, такие переменные как name и _age присутствуют в конце списка, а вот переменной __password нет. Что же с ней случилось? Интерпретатор искажает ее название на _Client__password.
Как же он искажает их? Вначале идет название класса с префиксом в виде нижнего подчеркивания, а затем сам атрибут класса _<ClassName>__<attr>, в нашем случае так: _Client__password. Это делается, чтобы защитить переменную от переопределения в подклассах.
Предлагаю создать дочерний класс, который будет наследоваться от Client и переопределим его атрибуты:
Получили исключение AttributeError! У нас нет возможности получить или изменить атрибут __password (обманул, такая возможность все же есть). Давайте посмотрим, как изменилось название этого атрибута:
Как и говорилось ранее, название изменилось точно также, как и изменилось название у родительского класса на _VipClient__password, и хотелось бы обратить внимание на присутствие переменной _Client__password, которая пришла от родителя и не была переопределена в дочернем объекте.
А теперь покажу, как все таки можно получить значение атрибута и изменить его вне класса (однако, в реальных проектах, таким заниматься не нужно, потому что этот атрибут не предназначен для использования вне класса и с большой долей вероятности, можно что-нибудь сломать):
Методы, также как и атрибуты, могут иметь префикс в виде двойного подчеркивания:
Как можно увидеть, метод назывался __get_password, а теперь это _Client__get_password. Искажение имен методов работает точно по такому же принципу, как и с именами атрибутов класса.
Двойной начальный и замыкающий символ подчеркивания: "__variable__"
Использование двойного начального и замыкающего символа подчеркивания обычно связано с так называемыми "магическими" или "дандер" методами и переменными. Эти методы и переменные имеют особое значение в языке и используются для реализации определенного поведения, например:
- __init__ - конструктор класса, вызывается при создании нового экземпляра класса;
- __str__ - определяет строковое представление объекта, возвращаемое функцией str();
- __repr__ - определяет строковое представление объекта, возвращаемое функцией repr();
- __add__ - определяет поведение оператора +;
Это далеко не все дандер методы, которые существую в Python, узнать больше можно тут.
Вы наверняка зададитесь вопросом, а в чем разница между __str__ и __repr__, ведь они оба определяют строковое представление объекта? Если вкратце, то __str__ , используется для пользователей, а __repr__ - для программистов, подробнее можно почитать тут.
Давайте рассмотрим пример, реализовав вышеописанные методы:
Заключение
В заключение хочу сказать, что подчеркивания в Python - это важный инструмент, который позволяет программистам явно выражать свои намерения. Понимание различных типов подчеркиваний и их влияния на поведение кода поможет вам писать более читаемый, поддерживаемый и надежный код.
- Одинарный начальный символ подчеркивания "_variable" - используется для обозначения внутренних атрибутов и методов, которые не предназначены для использования вне класса.
- Одинарный замыкающий символ подчеркивания "variable_" - используется для избежания конфликтов имен с ключевыми словами Python.
- Одинарный символ подчеркивания: "_" - используется для обозначения временных или незначительных переменных, а также для хранения результата последней операции в REPL.
- Двойной начальный символ подчеркивания "__variable" - используется для защиты атрибутов и методов от конфликтов имен в подклассах.
- Двойной начальный и замыкающий символ подчеркивания "__variable__" - используется для обозначения "магических" методов, которые определяют поведение классов.
Желаю сил и терпения в изучении такого прекрасного языка программирования как Python, до скорого!