Синтаксический сахар¶
Автор(ы)
Введение¶
Синтаксический сахар — это синтаксис, который позволяет разработчикам писать код проще, «сладким» способом. Следовательно, такой способ даёт роскошь не знать, как работает система под капотом. Синтаксический сахар связан не только с Python, подробнее по ссылке.
Раннее уже были изучены некоторые способы использования синтаксического сахара в Python, такие как:
- декораторы
- генераторы
- контекстные менеджеры
- f-строки (f-strings)
- списковое включение или генератор списков (list comprehensions)
Важно понимать и другие варианты применения такого функционала изучаемого языка.
Магические методы (Magic Methods)¶
Магические методы (иногда их ещё называют специальными методами) — это методы с предопределенными именами, характеризующимися двойным подчеркиванием в начале и в конце - __init__
как пример. Они являются «магическими», потому что
- эти методы вызываются косвенно
- не нужно вызывать напрямую
- все делается за кулисами
Например, когда создаётся экземпляр класса x = MyClass()
, Python выполнит необходимые вызовы __new__
и __init__
.
Пример¶
Как видно из примера, метод __repr__()
тесно связан с известной функцией print()
. Вот еще несколько примеров:
В этом разделе не будут подробно рассматриваться магические методы, если есть желание узнать больше о них - можно заглянуть в документацию (как пример для Python версии 3.11).
Являются ли магические методы синтаксическим сахаром?
Да!
Генератор словарей (dict-comprehension)¶
Операторы присваивания¶
Операторы сравнения¶
Тернарный оператор¶
Большие числа¶
Для удобства чтения большие числа можно записывать с использованием символа нижнего подчёркивания.
Многоточие (Ellipsis)¶
Python имеет специальный встроенный одноэлементный объект под названием Ellipsis
. Если вывести три точки или слово Ellipsis
в интерактивной оболочке Python, результаты будут следующими:
Этот простой предмет кажется незаметным, но если правильно его использовать, он может облегчить нашу жизнь. Рассмотрим три общих сценария, в которых можно использовать Ellipsis
.
Ellipsis
— это заполнитель для ненаписанного кода¶
При разработке нового модуля обычно определяются некоторые функции или классы, но не реализуются сразу. Потому что хочется только определить, что нужно написать в будущем, и не слишком заботимся о деталях реализации на раннем этапе. В таком сценарии Ellipsis
— наш лучший друг:
Можно просто использовать Ellipsis
в качестве заполнителя для функции или класса использую тождественный ...
pass
.
Вообще говоря, хорошей практикой программирования является то, что сначала проектируются необходимые функции или классы, а потом реализуются. Поэтому такой способ может помочь нашему уму ясно видеть всю структуру и не зацикливаться сразу на деталях.
Использование Ellipsis
в NumPy
, чтобы опустить размеры¶
NumPy
— важная библиотека Python для Data Science. Ellipsis
полезно при работе с многомерными массивами в NumPy
.
Например, если есть трёхмерная матрица и необходимо разделить её, то есть как минимум три способа как сделать это:
[[[0.992417 0.9530508 ]
[0.56965073 0.30738159]
[0.7711779 0.11873405]]
[[0.95767839 0.82798645]
[0.31408532 0.22584154]
[0.22445472 0.62915576]]]
Использование Ellipsis
(трёх точек) является наиболее экономичным способом разделения многомерной матрицы. Потому что это требует наименьшего набора текста. Время программистов — деньги, не так ли?
Использование Ellipsis
для подсказки типа¶
Подсказки типов были новым функционалом Python версии 3.5. На основе PEP 484 Ellipsis
имеет особое значение для этого функционала.
С одной стороны однородные кортежи произвольной длины могут быть выражены с помощью одного типа и Ellipsis
, например, Tuple[int, ...]
.
С другой стороны можно объявить возвращаемый тип вызываемого объекта без указания сигнатуры вызова, заменив Ellipsis
(три точки) на список аргументов:
Ellipsis
— интересный синтаксический сахар в Python. Его удобно использовать в некоторых сценариях.
Морж-оператор (walrus-operator)¶
Каждая новая версия Python добавляет в язык новые функции. Для Python 3.8 самым большим изменением было добавление выражений присваивания. В частности, оператор :=
дает новый синтаксис для присваивания переменных в середине выражений. Такой оператор в просторечии известен как морж-оператор.
Уже было упоминали ранее о существовании оператора :=
, полезно погрузиться в дополнительные возможности такого оператора.
Поговорим о том, как:
- определить морж-оператора и понять его значение
- понимать варианты использования морж-оператора
- избегать повторяющегося кода с помощью морж-оператора
- конвертировать код, использующий морж-оператора, в код, использующий другие методы присваивания и наоборот
- понимать влияния на обратную совместимость при использовании морж-оператора
- использовать соответствующий стиль в выражениях присваивания
Замечание
Для корректной работы морж-оператора требуется Python 3.8 или более поздней версии.
Основы морж-оператора¶
Оператор :=
официально известен как оператор выражения присваивания. Во время ранних дискуссий его назвали оператором моржа, потому что синтаксис :=
напоминает глаза и бивни лежащего на боку моржа. Также иногда можно увидеть, что оператор :=
называют «оператор двоеточие равно» (colon equals operator). Еще одним термином, используемым для выражений присваивания, являются именованные выражения.
Чтобы получить первое представление о том, что такое выражения присваивания, можно поэкспериментировать со следующим кодом:
В примере выше показан традиционный оператор присваивания, в котором переменной walrus
присваивается значение False
.
Затем, используется выражение присваивания, чтобы присвоить значение True
для walrus
. В обоих случаях можно ссылаться на присвоенные значения, используя имя переменной walrus
.
Между двумя типами присваиваний, рассмотренными выше с переменной walrus
, есть тонкая, но важная разница. Выражение присваивания возвращает значение, а традиционное присваивание — нет.
В этих примерах можно увидеть еще один важный аспект операторов моржа. Оператор :=
не делает ничего такого, что было бы невозможно без него. С помощью оператора моржа можно лишь делать определенные конструкции более удобными и иногда можно более четко передать цель кода.
Общее представление о том, что такое оператор :=
и что он может делать получено. Это оператор, используемый в выражениях присваивания, который может возвращать присваиваемое значение, в отличие от традиционных операторов присваивания.
Внимание
Один из принципов разработки, лежащий в основе оператора walrus, заключается в том, что не существует идентичных контекстов кода, в которых были бы допустимы как оператор присваивания, использующий оператор =
, так и выражение присваивания, использующее оператор :=
. Например, невозможно выполнить простое присваивание с помощью оператора walrus:
В большинстве случаев можно добавить круглые скобки ()
вокруг выражения присваивания, чтобы сделать код валидным:
Однако такая конструкция не имеет большого смысла, т.к. удобнее воспользоваться оператором =
. При этом запись традиционного оператора присваивания =
внутри таких скобок не допускается.
Варианты использования морж-оператора¶
Рассмотрим несколько примеров, где морж-оператора может упростить код. Общая тема всех этих примеров заключается в том, чтобы избегать различных видов повторения:
- повторные вызовы функций могут сделать код медленнее
- повторяющиеся операторы могут затруднить сопровождение кода
- повторяющиеся вызовы итераторов могут сделать код чрезмерно сложным
- увидим, как морж-оператор может помочь в каждой из этих ситуаций
Отладка¶
Возможно, один из лучших вариантов использования морж-оператора — отладка сложных выражений. Допустим, стоит задача найти расстояние между двумя точками на земной поверхности. Один из способов сделать это — использовать формулу гаверсинуса
:
где \(\varphi\) представляет широту, а \(\lambda\) - долготу каждого местоположения.
Чтобы продемонстрировать эту формулу, можно рассчитать расстояние между Москвой (55,45° с. ш., 37,36° в. д.) и Ванкувером (51,3° с. ш., 0,7° з. д.) следующим образом:
Как можно увидеть, расстояние от Москвы до Лондона составляет чуть более 2500 километров.
Теперь предположим, что нужно перепроверить реализацию и посмотреть, насколько члены гаверсинуса
влияют на конечный результат. Можно скопировать и вставить часть из основного кода, чтобы оценить его отдельно. Однако также можно использовать оператор :=
, чтобы дать имя интересующему подвыражению:
Преимущество использования морж-оператора здесь заключается в том, что одновременно можно вычислять значение итогового значения и отслеживаете значение ϕ_hav
. Это позволяет подтвердить, что не было допущено никаких ошибок во время отладки.
Списки и словари¶
Списки — это мощные структуры данных в Python, которые часто представляют собой ряд связанных атрибутов. Точно так же словари используются во всем Python и отлично подходят для структурирования информации.
Иногда при настройке таких структур данных приходится выполнять одну и ту же операцию несколько раз. В качестве первого примера вычислим некоторую базовую описательную статистику списка чисел и сохраним их в словаре:
Важно обратить внимание, что и сумма, и длина списка чисел вычисляются дважды. В этом простом примере последствия не так уж плохи, но если бы список был больше или вычисления были бы более сложными, вероятно захотелось бы оптимизировать такой код. Для этого можно сначала переместить вызовы функций из определения словаря:
Переменные num_length
и num_sum
используются только для оптимизации вычислений внутри словаря. Используя морж-оператор, эту роль можно сделать более понятной:
num_length
и num_sum
теперь определены внутри определения описания. Это явный намёк на то, что эти переменные используются только для оптимизации этих вычислений и больше не используются позже.
Замечание
Область видимости переменных num_length
и num_sum
одинакова в примере с морж-оператором и в примере без него. Это означает, что в обоих примерах переменные доступны после определения описания.
Несмотря на то, что оба примера функционально очень похожи, преимущество использования выражений присваивания заключается в том, что оператор :=
сообщает о назначении этих переменных как одноразовые оптимизации.
f-строки (f-strings)¶
О f-строках говорили ранее, полезно погрузиться в дополнительные возможности этого удобного и в последнее время наиболее часто используемого функционала для форматирования строк.
В большинстве случаев синтаксис аналогичен старому %
-форматированию с добавлением {}
и :
вместо %
. Например, %03.2f
можно перевести как {:03.2f}
.
Спецификаторы формата¶
Спецификаторы в f-строках можно использовать таким образом:
Спецификаторы формата могут содержать оцениваемые выражения. Это позволяет использовать следующий код:
После оценки выражений в спецификаторе формата (при необходимости) спецификаторы формата не интерпретируются оценщиком f-строки. Как и в str.format(), они просто передаются в метод format() форматируемого объекта.
Переменные со значениями¶
Версия Python 3.8 не обошла стороной и f-строки, дополнив их возможностями по выводу имён переменных вместе со значениями.
Как это работало до версии 3.8:
И как это стало работать начиная с версии Python 3.8:
Мини-язык спецификаций форматирования¶
Format Specification Mini-Language Python, поддерживаемый f-строками, позволяет реализовать множество операций форматирования данных.
Заполнение и центрирование текста¶
Предположим у нас есть следующая строка
Если добавить в неё:
- двоеточие,
- символ-заполнитель,
- указать требуемую длину строки с помощью
<
То не занятый текстом остаток строки будет заполнен выбранным символом-заполнителем:
Если указать длину строки через >
, то можно заполнить строку с левой стороны:
Как заполнить строку с обеих сторон, чтобы получилось ------ODS------
?
Замена %x
и %o
и преобразование значения в разные базы¶
Формат поддерживает двоичные числа
с префиксом 0x
, 0o
, или 0b
:
Разделитель групп разрядов¶
Выражение процента¶
Форматирование даты и времени¶
Добавление начальных нулей¶
Заключение¶
Как видно, синтаксический сахар облегчает жизнь программистам, и часто они даже не замечают или даже не знают, что используем его, но в любом случае всегда полезно знать, как он работает в деталях, потому что рано или поздно придётся глубже понять как работает та или иная вещь, чтобы успешно решать сложные задачи.