Новые фичи Python 3.8

Оригинал тут — https://realpython.com/python38-new-features/
И тут я тоже был — https://khashtamov.com/ru/python38-overview/

Сегодня 14 октября релизнулась новая версия Python 3.8. Рассмотрим новые всякие штуки в нем:

  • Использование выражений присваивания для упрощения кода;
  • Применение только позиционных аргументов в функциях;
  • Использование f-строк для простой отладки.

Морж в комнате: выражения присваивания

Самое большое изменение в Python 3.8 — это введение выражений присваивания. Обозначается он новой конструкцией (которая, правда, может быть знакома вам со времен Pascal) как (:=) без скобок. Этот оператор обычно называют моржовым оператором, т.к. напоминает глаза и клыки моржа (наркоманы херовы).

Это выражение присваивание дает нам возможность присваивать и возвращать значение в одном и том же выражении. Например, если необходимо присвоить выражение переменной и потом вывести ее значение, типичным кодом для этого может быть что-то такое:

>>> walrus = False
>>> print(walrus)
False

В новой версии Python такое же действие возможно, используя моржовый оператор:

>>> print(walrus := True)
True

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

Один из примеров, демонстрирующий силу моржового оператора — это циклы while, где необходимо инициализировать и обновлять переменную цикла вручную. Абстрактный пример, в котором будем постоянно просить что-то написать пользователя, пока это что-то не будет равно «quit»:

inputs = list()
current = input("Write something: ")
while current != "quit":
    inputs.append(current)
    current = input("Write something: ")

Код совсем не идеален. Вы повторяете оператор input (), и вам нужно каким-то образом добавить переменную current в список, прежде чем запрашивать ее у пользователя. Более красивое решение — использование бесконечного цикла while и оператора break:

inputs = list()
while True:
    current = input("Write something: ")
    if current == "quit":
        break
    inputs.append(current)

Этот код эквивалентен приведенному выше, но избегает повторения и, тем самым, сохраняет строки в более логичном порядке. Если вы используете новое выражение присваивания, вы можете еще больше упростить этот цикл:

inputs = list()
while (current := input("Write something: ")) != "quit":
    inputs.append(current)

Довольно изящно и соответствует философии языка. Тест цикла попал на его же строку, что читаемо. Тем не менее, сейчас в этой строке происходит несколько вещей одновременно, поэтому для правильного ее прочтения требуется немного больше усилий. Используйте новый моржовый оператор с умом, а за подробностями иди в PEP572.

Positional-Only Arguments

В python 3.8 появилась возможность задавать передачу аргументов исключительно согласно их позиции. В отличие от keyword-only arguments, все аргументы обязаны быть переданы согласно позиции:

def position_only(a, b, c, d=0, /):
    pass

position_only(1, 2, 3)  # OK

position_only(1, 2, c=3)  # вызов такой функции провоцирует исключение
Traceback (most recent call last):
  File "<pyshell#11>", line 1, in <module>
    position_only(1,2,c=3)
TypeError: position_only() got some positional-only arguments passed as keyword arguments: 'c'</module></pyshell#11>

Залезем немного глубже. Рассмотрим функцию float(), которая конвертирует числа и строки во float формат.

>>> float("3.8")
3.8

>>> help(float)
class float(object)
 |  float(x=0, /)
 |  
 |  Convert a string or number to a floating point number, if possible.

[...]

В выделенной строке есть что-то, похожее на присваивание и там же обратим внимание на слеш (/) после параметра функции. Что он значит?

За пониманием об использовании слеша / топайте в PEP457

Оказывается, что хотя один параметр float () называется x, вы не можете использовать его имя:

float(x="3.8")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: float() takes no keyword arguments

При использовании float () вам разрешено указывать аргументы только по позиции, а не по ключевому слову. До Python 3.8 такие Positional-Only аргументы были возможны только для встроенных функций. Не было простого способа указать, что аргументы должны быть Positional-Only в ваших собственных функциях:

>>> def incr(x):
...     return x + 1
... 
>>> incr(3.8)
4.8

>>> incr(x=3.8)
4.8

В предыдущих версиях можно было имитировать Positional-Only аргументы, используя * args, но это менее гибко, менее читабельно и заставляло вас реализовать собственный анализ аргументов. В Python 3.8 вы можете использовать /, чтобы обозначить, что все аргументы перед ним должны быть позиционно указаны. 

Как уже сказал, за подробностями отправляемся в указанный выше PEP.

Упрощенная отладка с помощью f-строк

f-строки, они же форматированные строки, появились в версии 3.6 и стали популярны. Вероятно, их появление — одна из причин, почему многие библиотеки поддерживают питон 3,6 и новее. f-строка — форматированный строковый литерал. Вы можете объявить ее следующим образом:

>>> style = "formatted"
>>> f"This is a {style} string"
'This is a formatted string'

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

>>> import math
>>> r = 3.6

>>> f"A circle with radius {r} has area {math.pi * r * r:.2f}"
'A circle with radius 3.6 has area 40.72'

Можно так же использовать выражения присваивания:

>>> import math
>>> r = 3.8

>>> f"Diameter {(diam := 2 * r)} gives circumference {math.pi * diam:.2f}"
'Diameter 7.6 gives circumference 23.88'

Однако, настоящая новость в Python 3.8 — это новый спецификатор отладки. Теперь вы можете добавить = в конце выражения, и оно напечатает как выражение, так и его значение:

>>> python = 3.8
>>> f"{python=}"
'python=3.8'

Вы можете добавить пробелы вокруг = и использовать спецификаторы формата как обычно:

>>> name = "Eric"
>>> f"{name = }"
"name = 'Eric'"

>>> f"{name = :>10}"
'name =       Eric'

Невероятно удобная вещь.

Ну и напоследок. Новая версия хороша, особенно отладочные возможности форматированных строк. Как всегда, полная информация об обновлении содержится в официальных источниках.

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

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