Сегодня, 05.10.2020 ожидается выход стабильной версии Python 3.9.0. Новая версия будет получать обновления с исправлениями примерно каждые 2 месяца в течение примерно 18 месяцев. Через некоторое время после выпуска финальной версии 3.10.0 будет выпущено девятое и последнее обновление с исправлением ошибок 3.9.

«This is the first version of Python to default to the 64-bit installer on Windows. The installer now also actively disallows installation on Windows 7.»
«Это первая версия Python, по умолчанию использующая 64-разрядный установщик в Windows. Программа установки теперь также запрещает установку в Windows 7.»

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

UPD:
Переход на стабильные годовые циклы выпуска, см. PEP 602
alec_kalinin
«Каждая новая версия Python теперь будет выходить в октябре. Python 3.10 выйдет в октябре 2021, Python 3.11 в октябре 2022. А каждые два месяца будет выходить бакфикс. Для меня это великолепная новость, теперь можно четко планировать upgrade python окружения.»

PEP 584


Этот PEP предлагает добавить операторы слияния ( | ) и обновления ( | = ) во встроенный класс dict.

Для слияния: |

>>> a = {'milk': 'prostokvashino', 'сheese': 'cheddar'} 
>>> b = {'milk': 1, 'сheese': 2, 'bread': 3} 
>> > а | b 
{'milk': 1, 'сheese': 2, 'bread': 3}
>>> b | a 
{'milk': 'prostokvashino', 'сheese': 'cheddar', 'bread': 3}

Для обновления: |=

>>> a | = b 
>>> a 
{'milk': 1, 'сheese': 2, 'bread': 3}

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

Безусловно, у многих питонистов возникнет вопрос, зачем это нужно, если уже есть привычный всем вариант

{**d1, **d2}

На этот вопрос был дан ответ в самом PEP:

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

Как сказал Гвидо:
Прошу прощения за PEP 448, но даже если вы знаете о ** d в более простом контексте, если бы вы спросили типичного пользователя Python, как объединить два dict в новый, я сомневаюсь, что многие люди подумают о {**d1, **d2}. Я знаю, что сам забыл об этом, когда началась эта ветка!

Также {**d1, **d2} не работает для подклассов dict, таких как defaultdict


PEP 585


Generics подсказки типов в стандартных коллекциях.

Generic — тип, который можно параметризовать, некий контейнер. Также известен как параметрический тип или универсальный тип.

В выпуске включена поддержка универсального синтаксиса во всех стандартных коллекциях, доступных в настоящее время в модуле «Typing». Мы можем использовать типы list или dict в качестве универсальных типов вместо использования typing.List или typing.Dict.

Было:

from typing import List

a: List[str] = list()

def read_files(files: List[str]) -> None:
    pass

Стало:

a: list[str] = list()

def read_files(files: list[str]) -> None:
    pass

Полный список типов
tuple
list
dict
set
frozenset
type
collections.deque
collections.defaultdict
collections.OrderedDict
collections.Counter
collections.ChainMap
collections.abc.Awaitable
collections.abc.Coroutine
collections.abc.AsyncIterable
collections.abc.AsyncIterator
collections.abc.AsyncGenerator
collections.abc.Iterable
collections.abc.Iterator
collections.abc.Generator
collections.abc.Reversible
collections.abc.Container
collections.abc.Collection
collections.abc.Callable
collections.abc.Set # typing.AbstractSet
collections.abc.MutableSet
collections.abc.Mapping
collections.abc.MutableMapping
collections.abc.Sequence
collections.abc.MutableSequence
collections.abc.ByteString
collections.abc.MappingView
collections.abc.KeysView
collections.abc.ItemsView
collections.abc.ValuesView
contextlib.AbstractContextManager # вместо typing.ContextManager
contextlib.AbstractAsyncContextManager # вместо typing.AsyncContextManager
re.Pattern # вместо typing.Pattern, typing.re.Pattern
re.Match # вместо typing.Match, typing.re.Match

PEP 615


Поддержка базы данных часовых поясов IANA в стандартной библиотеке.

IANA часовые пояса часто называют tz или zone info. Существует большое количество часовых поясов IANA с разными путями поиска для указания часового пояса IANA для объекта даты и времени. Например, мы можем передать имя пути поиска как Континент/Город datetime объекту, чтобы установить его tzinfo.

dt: datetime = datetime(2000, 01, 25, 01, tzinfo=ZoneInfo("Europe/London"))

Если мы передадим неверный ключ, будет вызвано исключение
zoneinfo.ZoneInfoNotFoundError

PEP 616


Новые строковые функции для удаления префикса и суффикса.

К str объекту добавлены две новые функции.

  • Первая функция удаляет префикс.
    str.removeprefix(prefix)
  • Вторая функция удаляет суффикс.
    str.removesuffix(suffix)

>>> 'hello_world'.removeprefix ('hello_') 
world
>>> 'hello_world'.removesuffix ('_world') 
hello

PEP 617


Версия Python 3.9 предлагает заменить текущий синтаксический анализатор Python на основе LL (1) новым синтаксическим анализатором на основе PEG, который является высокопроизводительным и стабильным.

Текущий парсер CPython основан на LL (1). Впоследствии грамматика основана на LL (1), что позволяет анализировать ее с помощью анализатора LL (1). Парсер LL (1) работает сверху вниз. Кроме того, он анализирует входные данные слева направо. Текущая грамматика является контекстно-свободной грамматикой, поэтому контекст токенов не принимается во внимание.
Версия Python 3.9 предлагает заменить его новым парсером на основе PEG, что означает, что он снимет текущие ограничения Python грамматики LL (1). Кроме того, в текущий синтаксический анализатор внесены исправления, в которые добавлен ряд хаков, которые будут удалены. В результате это снизит стоимость обслуживания в долгосрочной перспективе.

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

issue30966


Возможность отмены одновременных фьючерсов.

Новый параметр cancel_futures был добавлен в concurrent.futures.Executor.shutdown().

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

Новый параметр cancel_futures был добавлен в ThreadPoolExecutor и ProcessPoolExecutor. Он работает, когда значение параметра равно True, тогда все ожидающие фьючерсы будут отменены при вызове функции shutdown().

Когда shutdown() выполняется, интерпретатор проверяет, не собран ли исполнитель сборщиком мусора. Если он все еще находится в памяти, он получает все ожидающие обработки элементы, а затем отменяет фьючерсы.

issue30966


В этом выпуске в библиотеку asyncio и multiprocessing был внесен ряд улучшений.

Например,

  1. reuse_address параметр asyncio.loop.create_datagram_endpoint() больше не поддерживаются из-за значительных проблем в области безопасности.
  2. Добавлены новые coroutines, shutdown_default_executor() и сопрограммы asyncio.to_thread(). Новый вызов asyncio.to_thread() используется для запуска функций, связанных с вводом-выводом, в отдельном потоке, чтобы избежать блокировки цикла событий.

Что касается улучшений библиотеки multiprocessing, в класс multiprocessing.SimpleQueue был добавлен новый метод close().

Этот метод явно закрывает очередь. Это гарантирует, что очередь будет закрыта и не останется дольше ожидаемого. Важно помнить, что методы get(), put(), empty() нельзя вызывать после закрытия очереди.

issue37444


Исправление ошибки импорта пакетов.

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

builtins.__import__() вызывал ValueError то время как importlib.__import__() вызывал ImportError.

Сейчас это исправлено, . __Import __ () теперь вызывает ImportError вместо ValueError.

issue40286


Генерация случайных байтов.

Еще одна функция, которая была добавлена ??в версии 3.9, — это random.Random.randbytes(). Она может использоваться для генерации случайных байтов.

Мы можем генерировать случайные числа, но что, если нам нужно было генерировать случайные байты? До версии 3.9 разработчикам приходилось проявлять изобретательность, чтобы генерировать случайные байты. Хотя мы можем использовать, os.getrandom(), os.urandom() или secrets.token_bytes() но не можем генерировать псевдослучайные шаблоны.

Например, чтобы гарантировать, что случайные числа генерируются с ожидаемым поведением и процесс воспроизводится, мы обычно используем seed с модулем random.Random.

В результате был введен метод random.Random.randbytes(). Он генерирует случайные байты.

issue28029


Исправление функции замены строки.

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

Чтобы дополнительно объяснить проблему, до версии 3.9 функция replace имела несогласованное поведение:

Можно было бы ожидать увидеть blog

"" .replace ("", "blog", 1) 
>>> '' 


Можно было бы ожидать увидеть |

"" .replace ("", "|", 1) 
>>> '' 


"" .replace ("", "prefix") 
>>> 'prefix'


issue39648, issue39479, issue39288, issue39310


Изменения в модуле «math».

Возвращает наименьшее общее кратное целых аргументов:

>>> import  math 
>>> math.lcm(48,72,108) 
432


Возвращает наибольший общий делитель целочисленных аргументов. В более ранней версии поддерживалось только два аргумента. Добавлена ??поддержка произвольного количества аргументов:

>>> import  math 
>>> math.gcd(9,12,21) 
3


Вычисляет ближайшее к "x" число с плавающей точкой, если двигаться в направлении "y".

>>> math.nextafter(2, -1)
1.9999999999999998


Этот метод возвращает значение младшего бита числа с плавающей запятой x.

>>> 1 - math.ulp(1)
0.9999999999999998
>>> math.nextafter(1, -1) + math.ulp(1)
1.0


issue38870


В модуль ast добавили метод unparse.
Новый метод может использоваться для создания строки с кодом и его последующего выполнения.

>>> import ast
>>> parsed = ast.parse('from sys import platform; print(platform)')
>>> unparsed_str = ast.unparse(parsed)
>>> print(unparsed_str)
from sys import platform
print(platform)
>>> exec(unparsed_str)
win32


issue39507, issue39509


Добавление новых кодов в http.HTTPStatus.

"Сохранить 418!"
418 IM_A_TEAPOT
103 EARLY_HINTS
425 TOO_EARLY


UPD:

PEP 614


Ослабление грамматических ограничений для декораторов.

Было:

buttons = [QPushButton(f'Button {i}') for i in range(10)]

button_0 = buttons[0]

@button_0.clicked.connect
def spam():
    ...

button_1 = buttons[1]

@button_1.clicked.connect
def eggs():
    ...

То теперь можно убрать лишние присваивания и вызывать напрямую:

buttons = [QPushButton(f'Button {i}') for i in range(10)]

@buttons[0].clicked.connect
def spam():
    ...

@buttons[1].clicked.connect
def eggs():
    ...


«Кортеж должен быть заключен в круглые скобки»

Это основано на видении Гвидо в том же письме. Цитата:

Но запятых я не допущу. Я не могу согласиться с этим

@f, g
def pooh(): ...

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


issue17005


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

UPD: ifinik
image

>>> from graphlib import TopologicalSorter 
>>> graph = {'E': {'C', 'F'}, 'D': {'B', 'C'}, 'B': {'A'}, 'A': {'F'}} 
>>> ts = TopologicalSorter(graph) 
>>> tuple(ts.static_order()) 
('C', 'F', 'E', 'A', 'B', 'D')
>>> tuple(ts.static_order())
('F', 'C', 'A', 'E', 'B', 'D')

Граф можно передавать не сразу, а заполнять TopologicalSorter с помощью метода add. Кроме того класс адаптирован к параллельным вычислениям и может быть использован, например, для создания очереди задач.

issue37630, issue40479


Обновление библиотеки hashlib.
Теперь hashlib может использовать хэши SHA3 и SHAKE XOF из OpenSSL.
Встроенные хэш-модули теперь могут быть отключены или выборочно включены, например, для принудительного использования реализации на основе OpenSSL.

Оптимизация


Сводка улучшений производительности от Python 3.4 до Python 3.9:

Python version                       3.4     3.5     3.6     3.7     3.8    3.9
--------------                       ---     ---     ---     ---     ---    ---

Variable and attribute read access:
    read_local                       7.1     7.1     5.4     5.1     3.9    4.0
    read_nonlocal                    7.1     8.1     5.8     5.4     4.4    4.8
    read_global                     15.5    19.0    14.3    13.6     7.6    7.7
    read_builtin                    21.1    21.6    18.5    19.0     7.5    7.7
    read_classvar_from_class        25.6    26.5    20.7    19.5    18.4   18.6
    read_classvar_from_instance     22.8    23.5    18.8    17.1    16.4   20.1
    read_instancevar                32.4    33.1    28.0    26.3    25.4   27.7
    read_instancevar_slots          27.8    31.3    20.8    20.8    20.2   24.5
    read_namedtuple                 73.8    57.5    45.0    46.8    18.4   23.2
    read_boundmethod                37.6    37.9    29.6    26.9    27.7   45.9

Variable and attribute write access:
    write_local                      8.7     9.3     5.5     5.3     4.3    4.2
    write_nonlocal                  10.5    11.1     5.6     5.5     4.7    4.9
    write_global                    19.7    21.2    18.0    18.0    15.8   17.2
    write_classvar                  92.9    96.0   104.6   102.1    39.2   43.2
    write_instancevar               44.6    45.8    40.0    38.9    35.5   40.7
    write_instancevar_slots         35.6    36.1    27.3    26.6    25.7   27.7

Data structure read access:
    read_list                       24.2    24.5    20.8    20.8    19.0   21.1
    read_deque                      24.7    25.5    20.2    20.6    19.8   21.6
    read_dict                       24.3    25.7    22.3    23.0    21.0   22.5
    read_strdict                    22.6    24.3    19.5    21.2    18.9   21.6

Data structure write access:
    write_list                      27.1    28.5    22.5    21.6    20.0   21.6
    write_deque                     28.7    30.1    22.7    21.8    23.5   23.2
    write_dict                      31.4    33.3    29.3    29.2    24.7   27.8
    write_strdict                   28.4    29.9    27.5    25.2    23.1   29.8

Stack (or queue) operations:
    list_append_pop                 93.4   112.7    75.4    74.2    50.8   53.9
    deque_append_pop                43.5    57.0    49.4    49.2    42.5   45.5
    deque_append_popleft            43.7    57.3    49.7    49.7    42.8   45.5

Timing loop:
    loop_overhead                    0.5     0.6     0.4     0.3     0.3    0.3

Сценарий теста отображает время в наносекундах. Тесты были выполнены на процессоре Intel Core i7-4960HQ. Код теста можно найти в репозитории по адресу "Tools/scripts/var_access_benchmark.py".

Благодарю за внимание.

Ссылка на официальное руководство Python 3.9.
Отпишитесь в комментарии, если что-то было упущено.