Подчеркивание в Python

от автора

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

Рассмотрим возможный вопрос по смайликам при собеседовании на должность, подразумевающую знание языка программирования Python.

Задача

Имеются два выражения:

  1. _+_
  2. _|_

Какое из этих двух выражений чаще будет приводить к возникновению ошибки и почему?

Замечания к выражениям

Следует отметить, что данные выражения плохо читаются, такие выражения не целесообразно использовать в рабочем коде, а можно использовать только в качестве головоломки.
Также нужно помнить, что смайлики в задаче написаны не питонично (не соответствуют стандарту стиля PEP 8).

Решение

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

Задача сводится к рассмотрению случаев появления ошибок при сложении и при «побитовом или» (для краткости — просто «или») одной переменной. Т.е. к поиску встроенных типов (классов) Python для которых реализована одна операция и к поиску встроенных типов где реализована другая операция.

В консоли Python легко проверить, что существуют такие значения подчеркивания при которых:

  1. В вычислении каждого выражения нет ошибки

    >>> _ = 10 >>> _+_ 20 >>> _ = 10 >>> _|_ 10
  2. В вычислении первого выражения нет ошибки

    >>> _ = '10' >>> _+_ '1010' >>> _ = '10' >>> _|_ Traceback (most recent call last):   File "<stdin>", line 1, in <module> TypeError: unsupported operand type(s) for |: 'str' and 'str'
  3. В вычислении второго выражения нет ошибки

    >>> _ = {1, 0} >>> _+_ Traceback (most recent call last):   File "<stdin>", line 1, in <module> TypeError: unsupported operand type(s) for +: 'set' and 'set' >>> _|_ {0, 1}
  4. В вычислении каждого выражения — ошибка

    >>> _ = {1: 0} >>> _+_ Traceback (most recent call last):   File "<stdin>", line 1, in <module> TypeError: unsupported operand type(s) for +: 'dict' and 'dict' >>> _|_ Traceback (most recent call last):   File "<stdin>", line 1, in <module> TypeError: unsupported operand type(s) for |: 'dict' and 'dict'

Магия Python заключается в том, что реализация и сложения, и «или», и других операторов находится в, так называемых, «магических методах», описанных для требуемых классов.
Для сложения это метод

__add__

Для «или» это метод

__or__

В названии каждого магического метода присутствуют символы подчеркивания, по два в начале и в конце соответствующего слова.

Поиск информации о встроенных классах Python.

Можно пытаться отыскать требуемую информацию в документации к встроенным типам на официальном сайте Python: https://docs.python.org/3.7/library/stdtypes.html.
Можно в терминале Python выполнить

>>> import builtins >>> help(builtins)

Я предпочитаю использовать документацию именно той версии Python, которую я использую в данный момент, обращаясь к web-интерфейсу модуля pydoc.

Для этого в командной строке вводим, например:

python3 -m pydoc -p 3344

и открываем в браузере документацию модуля http://localhost:3344/builtins.html.

Встроенные классы, для которых реализованы наши методы:

__add__ __or__
bool bool
bytearray frozenset
bytes int
complex set
float
int
list
str
tuple

Девять встроенных классов реализуют операцию сложения и четыре реализуют «или».
Дополнительно можно попытаться порассуждать про частоту использования базовых классов в реальных проектах, про небазовые классы и реализацию указанных выше методов для них. Вероятно, это будет положительно оценено при собеседовании.

Ответ 1.

Второе выражение чаще будет приводить к возникновению ошибки.


Возможные дополнительные вопросы про подчеркивание на собеседовании

Какова роль подчеркивания в именовании объектов?

Ответ 2.

Символ подчеркивания может использоваться для разделения слов в разных стилях именования сущностей в Python:

  1. При именовании в нижнем регистре
    lower_case_with_underscores
  2. При именовании в верхнем регистре
    UPPER_CASE_WITH_UNDERSCORES

Некоторые имена, ограниченные символами подчеркивания, являются зарезервированными:

  1. С символом подчеркивания в начале имени не импортируется при общем импорте
    from module import *
  2. С двумя символами подчеркивания с обеих сторон имени считается системным, не рекомендуется использовать такие имена в других целях
  3. С двумя символами подчеркивания в начале имени считается приватным (не публичным) для класса

Какова роль отдельного символа подчеркивания?

Ответ 3.

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

$ python3 Python 3.6.8 (default, Feb 14 2019, 22:09:48) [GCC 7.4.0] on cygwin Type "help", "copyright", "credits" or "license" for more information. >>> _ Traceback (most recent call last):   File "<stdin>", line 1, in <module> NameError: name '_' is not defined >>> 2 * 5 10 >>> _ 10 >>> _ = 1 >>> _ 1 >>> 2 * 5 10 >>> _ 1

Это связано с тем, что sys.stdout экранируется с помощью displayhook. Возьмем пример из официальной документации:

def displayhook(value):     if value is None:         return     # Set '_' to None to avoid recursion     builtins._ = None     text = repr(value)     try:         sys.stdout.write(text)     except UnicodeEncodeError:         bytes = text.encode(sys.stdout.encoding, 'backslashreplace')         if hasattr(sys.stdout, 'buffer'):             sys.stdout.buffer.write(bytes)         else:             text = bytes.decode(sys.stdout.encoding, 'strict')             sys.stdout.write(text)     sys.stdout.write("\n")     builtins._ = value

Кроме того единичное подчеркивание принято использовать для удобства интернализации.


ссылка на оригинал статьи https://habr.com/ru/post/459672/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *