Рассмотрим наиболее интересные дополнения и изменения, которые были внесены в язык Python с релизом 3.8.
Walrus operator
Введение walrus operator – это, наверное, наиболее значимое изменение, которое принес с собой Python 3.8. Этот оператор (выглядит он так (:=)) позволяет присваивать значение переменной в выражении. Таким образом код становится ещё более лаконичным.
Рассмотрим несколько примеров.
Присвоение внутри арифметического выражения:
>>> # Python <= 3.7 >>> a = 5 >>> b = 7 >>> c = a + b >>> print('a = {}, b = {}, c = {}'.format(a, b, c)) a = 5, b = 7, c = 12 >>> # Python 3.8 >>> c = (a := 5) + (b := 7) >>> print('a = {}, b = {}, c = {}'.format(a, b, c)) a = 5, b = 7, c = 12
Присвоение внутри условного оператора:
>>> a = [1, 2, 3, 4, 5] >>> if ((n := len(a)) >= 3): print(f"len = {n} high then limit") len = 5 high then limit
Присвоение внутри оператора цикла while:
>>> while ((msg := input()) != 'q'): print(f"> {msg}") test > test hello > hello q
Обратите внимание, выражение с оператором walrus должно быть помещено в скобки. Более подробное см. PEP 572
Positional-only arguments
Еще одни нововведением в синтаксисе является возможность определить для ряда аргументов функции только позиционную передачу значений. Как известно, в Python, можно использовать имена аргументов при передачи значений в функцию:
Создадим функцию:
>>> def print_pair(x, y): print(f"({x}, {y})")
Для этой функции возможны следующие варианты вызова:
>>> print_pair(1, 2) (1, 2) >>> print_pair(1, y=2) (1, 2) >>> print_pair(x=1, y=2) (1, 2) >>> print_pair(y=2, x=1) (1, 2)
Если необходимо запретить возможность именовать аргументы при вызове переменной, то для этого в Python 3.8 можно использовать специальный символ: ‘/’:
>>> def print_pair(x, y, /): print(f"({x}, {y})")
В этом случае будет возможен только один вариант вызова функции:
>>> print_pair(1, 2) (1, 2)
Другие (с именованием аргументов) будут недоступны:
>>> print_pair(1, y=2) Traceback (most recent call last): File "<pyshell#44>", line 1, in <module> print_pair(1, y=2) TypeError: print_pair() got some positional-only arguments passed as keyword arguments: 'y' >>> print_pair(x=1, y=2) Traceback (most recent call last): File "<pyshell#45>", line 1, in <module> print_pair(x=1, y=2) TypeError: print_pair() got some positional-only arguments passed as keyword arguments: 'x, y'
Более подробное см. PEP 570
f-строки: поддержка метки “=”
Следующее новшество касается f-строк: добавлена метка “=”, которая используется следующим образом f'{expr=}’. В результате будет вычислено выражение и этот результат будет присвоен текстовому представлению выражения. Примеры:
>>> name = "John" >>> age = 10 >>> # Python <= 3.7 >>> print(f"name='{name}', age={age}") name='John', age=10 >>> # Python 3.8 >>> print(f"{name=}, {age=}") name='John', age=10
Пример с вычислением:
>>> print(f"{4+5=}") 4+5=9
Новые типы: TypedDict, Literal, Final, Protocol
TypedDict
Для аннотации переменных типа dict с известным набором и типом элементов можно использовать TypedDict, для этого создайте класс-наследник от TypedDict:
>>> from typing import TypedDict >>> class Persone(TypedDict): name: str age: int
После этого имя класса можно использовать как тип в аннотации:
>>> user: Persone = {'name': 'Alex', 'age': 32} >>> user {'name': 'Alex', 'age': 32}
Literal
Literal используется, если нужно указать, что переменная должна принять значение из заданного набора:
def get_status(port: int) -> Literal['connected', 'disconnected']: ...
Final
Final используется для указания на то, что переменная (или атрибут) не подлежит изменению или переопределению:
from typing import Final # Пример с переменной PI: Final = 3.14 PI = 4 # Будет вызвана ошибка при проверке типов # Пример с атрибутом класса class Port: TIMEOUT: Final[int] = 1000 class SerialPort(Port): TIMEOUT = 500 # Будет вызвана ошибка при проверке типов
Protocol
Базовый класс для классов протоколов. Классы протокола определяются следующим образом:
class Engine(Protocol): def start(self) -> bool: ...
Пример использования протокола:
class SteamEngine: def start(self) -> bool: return True def test(x: Engine) -> bool: return x.start() test(SteamEngine())
Дополнительная информация
Дополнительно по новшествам Python 3.8 можете прочитать здесь:
https://realpython.com/python38-new-features/