Что Python 3.9 нам готовит? Новые фичи первой бета-версии

19 мая состоялся релиз Python 3.9.0 beta1. Нововведения, которые включены в данную бету, с высокой вероятностью попадут в итоговый релиз. Небольшие изменения в функционале возможны до выпуска release candidate, который запланирован на 10.08.2020. Но появление новых фич уже не планируется.

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

Вводится новый оператор объединения словарей


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

  • Метод dict.update.
    Данный метод модифицирует словарь, к которому применяется. Например, выражение dict_1.update(dict_2) изменяет словарь dict_1. Это не всегда удобно на практике.
  • Использование распаковки вида {**d1, **d2}

    В PEP 584 привели цитату Гвидо, который сказал о том, что «даже если пользователи Python знакомы с использованием конструкции распаковки **d в другом контексте, он сомневается, что они смогут сходу предложить такой способ объединения словарей». Гвидо признается, что и сам забыл про этот способ.

    К тому же, конструкция {**d1, **d2} игнорирует mapping-типы. Поэтому не все подклассы dict будут совместимы с ней (например, collections.defaultdict не может быть использован).
  • Использование collections.ChainMap

    Данный класс не очень распространен, и многие считают его неочевидным. Если в объединяемых словарях есть дубликаты, то все они будут храниться в ChainMap. А при изменении значения по ключу, будет изменяться только первый найденный элемент. Кроме того, как и в случае с распаковкой, есть проблемы совместимости с подклассами dict.

    >>> from  collections import ChainMap
    >>> dict_1 = { 'key_1': 1, 'key_2': 2 }
    >>> dict_2 = { 'key_1': 10, 'key_3': 3 } 
    
    >>> chain = ChainMap(dict_1, dict_2)
    >>> chain
    ChainMap({'key_1': 1, 'key_2': 2}, {'key_1': 10, 'key_3': 3})
    
    >>> chain['key_1'] = 999 # Изменяется только первый найденный элемент
    ChainMap({'key_1': 999, 'key_2': 2}, {'key_1': 10, 'key_3': 3})
    

  • Использование конструкции dict(dict_1, **dict_2)

    Также не очень распространенный метод. К тому же, в этом случае требуется чтобы dict_2 был только со строковыми ключами.

    >>> dict_1 = {'key_1': 1}
    >>> dict_2 = {2: 2}
    >>> dict(dict_1, **dict_2)
    TypeError: keywords must be strings
    


В Python 3.9 добавляется оператор объединения словарей |, работу которого легче всего продемонстрировать на примере:

>>> dict_1 = {'key_1': 1, 'key_2': 2}
>>> dict_2 = {'key_1': 99, 'key_3': 3}
>>> dict_1 | dict_2
{'key_1': 99, 'key_2': 2, 'key_3': 3}
>>> dict_2 | dict_1
{'key_2': 2, 'key_1': 1, 'key_3': 3}

То есть операция объединения не является коммутативной. Если в объединяемых словарях имеются одинаковые ключи, значение берется из последнего операнда. Также поддерживается расширенный оператор присваивания |=.

>>> dict_1 |= dict_2
>>> dict_1
{'key_1': 99, 'key_2': 2, 'key_3': 3}

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


Стандартный тип str получил пару новых методов для удаления префикса и суффикса:

>>> text = 'test_name'
>>> text.removeprefix('test_')
'name'

>>> text = 'name_test'
>>> text.removesuffix('_test')
'name'

Упрощается аннотирование типов (type hinting)


Авторы говорят о том, что исторически сформировалось, по сути, две дублирующих иерархии типов. При аннотировании была необходимость импорта типов из модуля typing. Такое указание типов становится устаревшим:

from typing import Dict, List
def func(arg: Dict[str, List[str]]) -> int:
    pass

Начиная с версии 3.7 можно было использовать конструкцию from __future__ для отложенной обработки аннотаций, что позволяет использовать типы стандартных коллекций:

from __future__ import annotations
def func(arg: dict[str, list[str]]) -> int:
    pass

И, с приходом версии 3.9, можно будет полностью перейти на аннотирование через стандартные коллекции. Как указано в PEP 585, поддержка устаревшей функциональности будет удалена из модуля typing через 5 лет после выпуска Python 3.9.

Полный список типов, которые можно будет использовать
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


Гибкие аннотации функций и переменных


В модуль typing добавляется тип Annotated, с помощью которого можно добавлять существующим типам контекстно-зависимые метаданные. Использование конструкции Annotated[T, x] означает, что тип T аннотируется метаданными x. Например:

my_type = Annotated[int, ValueRange(-100, 100)]

Подробное описание данной, достаточно специфичной темы приводится в PEP 593 Flexible function and variable annotations.

А так же...


Кроме описанных выше изменений, в версии 3.9 исправлены ряд багов и упоминается об ускорении работы встроенных типов range, tuple, set, frozenset, list, dict.

В рамках PEP 617 анонсирован новый PEG-парсер грамматики для CPython. Он приходит на смену LL(1)-парсера и расширяет возможности языка, поддерживая более сложные и гибкие грамматические конструкции выражений.

Также в PEP 602 объявлено, что начиная с версии 3.9, выпуск новых версий будет осуществляться раз в год, а цикл разработки каждой новой версии (3.10, 3.11 и т.д.) будет занимать 17 месяцев. Стабильность — залог успеха!

image
Tags:
python 3.9, python, новости, python3.9

You can't comment this post because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author's username will be hidden by an alias.