Как и большинство поклонников Python, я очень рад изучать и использовать новейшие функции. В этой статье будет представлен обзор возможностей Python 3.9, которые необходимо знать.
Я ознакомился с примечаниями к выпуску, посмотрел обсуждения и составил исчерпывающий гайд о том, что из себя представляют эти функции и как они работают.
Было добавлено несколько новых функций, включая объединение и обновление словарей, строковые методы и внедрение модуля zoneinfo. Также нам представили стабильный и высокопроизводительный парсер.
Давайте разбираться с нововведениями.
1. Операторы обновления и слияния словарей
Во встроенный класс dict добавлено два оператора: | и |=.
| используется для объединения словарей, |=– для их обновления.
В случае конфликта ключей верным будет считаться крайнее правое значение. Это соответствует поведению аналогичных операций dict .
Более детально
Как мы видим, добавлены новые операторы | и |=.
| можно рассматривать как оператор + (сложения) в списках, а |=– как оператор +=(расширения).
В Python 3.8 есть несколько способов слияния и обновления словарей.
К примеру, можно использовать first_dict.update(second_dict) . Проблема этого метода в том, что он изменит first_dict на месте. Чтобы этого избежать, нужно объявить временную переменную, сохранить в ней first_dict , а затем выполнить операцию обновления. Но появляется лишняя строка кода, просто чтобы оператор объединения/обновления работал.
Также мы можем применить <**first_dict, **second_dict>. Сложность этого метода в том, что его трудно обнаружить и сложнее понять смысл кода. Кроме того, исключаются типы mapping и учитывается только тип dict. Например, если first_dict – это defaultdict , а second_dict – это тип dict , то программа завершится ошибкой.
Этот способ не работает с подклассами dict , которые содержат функцию _init_ .
Наконец, библиотека collections содержит функцию ChainMap . Она может принять два словаря, как ChainMap(first_dict, second_dict) , и вернуть объединенный словарь, но об этой библиотеке знают немногие.
Для получения более подробной информации вы можете ознакомиться с источником.
2. Новый высокопроизводительный парсер на основе PEG
С Python 3.9 можно отказаться от использования LL (1) в пользу более гибкого и стабильного синтаксического анализатора на основе PEG.
Более детально
Текущий парсер CPython основан на LL (1). Грамматика основана на LL (1), что позволяет парсить ее с помощью LL (1) анализатора. Парсер LL (1) работает сверху вниз и анализирует входные данные слева направо. Грамматика является контекстно-свободной, поэтому контекст токенов не учитывается.
Python 3.9 предлагает заменить его новым парсером на основе PEG, который снимет ограничения Python грамматики LL (1). Будет удален ряд хаков, существующих в текущем синтаксическом анализаторе. В долгосрочной перспективе это снизит стоимость обслуживания.
Несмотря на то, что синтаксические анализаторы и грамматики LL (1) просты в реализации, ограничения не позволяют им выражать общие конструкции естественным образом для разработчика языка и читателя. Парсер смотрит только на один токен вперед, чтобы различать возможности.
Оператор выбора | упорядоченный. Рассмотрим следующее правило:
Контекстно-свободный парсер грамматики LL (1) будет генерировать конструкции, которые при заданной входной строке определят, нужно ли расширять A, B или C. Анализатор PEG отличается. Он проверит, успешна ли первая переменная, и только в случае провала перейдет ко второй или третьей.
Парсер PEG генерирует ровно одно допустимое дерево для строки. Он определенный, в отличие парсер LL (1).
Синтаксический анализатор PEG также напрямую генерирует узлы AST для правила через грамматические действия. За счет этого удается избежать создания промежуточных шагов.
Парсер PEG был тщательно протестирован. У него отлажена производительность. Поэтому для большинства инструкций он расходует примерно 10% от объема памяти и вычислительных ресурсов текущего анализатора. Все благодаря тому, что не создается промежуточное синтаксическое дерево.
Я опустил некоторые детали, чтобы не усложнять прочтение статьи. Для получения более подробной информации вы можете ознакомиться с источником.
3. Новые строковые функции для удаления префикса и суффикса
К объекту str добавлено две новых функции.
1. Первая удаляет префикс – str.removeprefix(‘префикс’) .
2. Вторая удаляет суффикс – str.removesuffix(‘суффикс’) .
Более детально
Одна из обыденных задач в приложении data science, которое включает в себя манипулирование текстом – удалить префикс/суффикс строк. Добавленные к объекту str функции можно использовать для удаления ненужных префиксов и суффиксов из строки.
Как мы уже знаем, первая функция удаляет префикс. Это str.removeprefix(‘префикс’) . Вторая функция удаляет суффикс. Это str.removesuffix(‘суффикс’) .
Строка – это набор символов, и каждый символ имеет индекс в строке. Индексы можно использовать вместе с : , чтобы вернуть подмножество строки. Эта функция известна как slice (срез) строки.
Если мы говорим о функциях, они проверяют, начинается ли строка с префикса (заканчивается ли она суффиксом), и если да, то возвращают строку без префикса или после суффикса, используя функцию среза str[:] .
Поскольку эти функции являются частью стандартной библиотеки, мы получаем согласованный, менее хрупкий, высокопроизводительный и более наглядный API.
Для получения более подробной информации вы можете ознакомиться с источником.
4. Подсказки типов для встроенных универсальных типов
Аннотирование программ стало проще за счет удаления иерархии параллельных типов в Python.
Добавлена поддержка универсального синтаксиса во всех стандартных коллекциях, доступных в модуле набора текста.
Мы можем использовать встроенные типы коллекций list или dict в качестве универсальных типов вместо использования typing.List или typing.Dict в сигнатуре нашей функции.
Код стал выглядеть чище, а его понимание и объяснение упростилось.
Более детально
Несмотря на то, что Python – это язык с динамической типизацией, аннотация типов в программе позволяет проводить самоанализ. Впоследствии аннотацию можно использовать для создания API проверки типов во время выполнения.
Как я говорил ранее, в Python 3.9 добавили поддержку универсального синтаксиса во всех стандартных коллекциях, доступных в модуле набора текста.
Универсальный тип – это обычно контейнер, к примеру list . Это тип, который можно параметризовать. Параметризованный тип – это пример универсального дженерика с ожидаемыми типами для элементов контейнера типа list[str] .
Мы можем использовать встроенные типы коллекций list или dict в качестве универсальных типов вместо использования typing.List или typing.Dict .
Например, мы могли бы управлять проверкой типов среды выполнения Python, аннотируя код:
Ряд функций статической типизации был постепенно построен поверх существующей среды выполнения Python. Некоторые из них были ограничены существующим синтаксисом и поведением во время выполнения. Поэтому в модуле типизации возникла дублированная иерархия коллекций из-за дженериков.
Например, мы увидим typing.List , typing.Dictionary вместе со встроенными list , dictionary и т. д. Это позволяет писать код:
Для получения более подробной информации вы можете ознакомиться с источником.
5. Поддержка часового пояса IANA в DateTime
Модуль zoneinfo был создан в качестве поддержки базы данных часовых поясов IANA. Эта поддержка была добавлена в стандартную библиотеку.
Часовые пояса IANA часто называют tz или zone info. Существует много часовых поясов IANA с разными путями поиска для указания часового пояса IANA объекта datetime . Например, мы можем передать имя пути поиска объекту datetime как Continent/City , чтобы установить его tzinfo .
dt=datetime(2000, 01, 25, 01, tzinfo=ZoneInfo(«Europe/London»))
Если мы передадим неверный ключ, возникнет ошибка zoneinfo.ZoneInfoNotFoundError .
Более детально
Библиотека datetime используется для создания объекта datetime и указания его часового пояса, путем установки свойства tzinfo . Все может обернуться созданием сложных правил часового пояса при использовании базового показателя datetime.tzinfo .
В большинстве случаев нужно просто установить объект и его часовой пояс: UTC, локальный часовой пояс системы, или часовой пояс IANA.
Можно создать объект zoneinfo.ZoneInfo(key) , где ключ имеет строковый тип, указывающий путь поиска файла зоны в базе данных часовых поясов системы. Объект zoneinfo.ZoneInfo(key) может быть создан и установлен как свойство tzinfo объекта datetime .
Для получения более подробной информации вы можете ознакомиться с источником.
6. Возможность отмены одновременных фьючерсов.
В concurrent.futures.Executor.shutdown() добавлен новый параметр cancel_futures .
Он отменяет все отложенные фьючерсы, которые не были запущены.
До версии 3.9 процесс ожидал их завершения перед завершением работы исполнителя.
Пояснение
Новый параметр cancel_futures был добавлен в ThreadPoolExecutor и ProcessPoolExecutor . Это работает так: если его значение – True , все ожидающие фьючерсы отменяются при вызове функции shutdown() .
При выполнении shutdown() интерпретатор проверяет, не собран ли исполнитель сборщиком мусора. Если он все еще находится в памяти, он получает все ожидающие обработки элементы, а затем отменяет фьючерсы.
Когда не остается незавершенных рабочих элементов, он завершает работу.
Для получения более подробной информации вы можете ознакомиться с источником.
7. Улучшения AsyncIO и многопроцессорности
В библиотеку asyncio и многопроцессорную обработку были внесен ряд улучшений.
1. Параметр reuse_address asyncio.loop.create_datagram_endpoint() больше не поддерживается из-за серьезных пробелов в безопасности.
2. Добавлены новые сопрограммы: shutdown_default_executor() и asyncio.to_thread(). shutdown_default_executor назначает завершение работы для исполнителя по умолчанию, который ждет завершения ThreadPoolExecutor. asyncio.to_thread() в основном используется для запуска функций, связанных с вводом-выводом, в отдельном потоке, чтобы избежать блокировки цикла событий.
Что касается улучшений библиотеки многопроцессорности, в класс multiprocessing.SimpleQueue был добавлен новый метод close() .
Этот метод точно закрывает очередь. Это гарантирует, что очередь будет закрыта и не останется дольше ожидаемого. Помните, что методы get() , put() , empty() не должны вызываться после закрытия очереди.
Для получения более подробной информации вы можете ознакомиться с источником.
8. Постоянные ошибки импорта пакетов
Основная проблема импортирования библиотек Python заключалась в несогласованном поведении, когда относительный импорт проходил мимо пакета верхнего уровня.
Встроенная функция __import__() вызывает ошибку ValueError , а importlib.__import__() вызывает ошибку ImportError .
Теперь это исправили. __import__() вызывает ImportError вместо ValueError .
Для получения более подробной информации вы можете ознакомиться с источником.
9. Генерация случайных байтов
Еще одна функция, добавленная в версии 3.9 – random.Random.randbytes() . Эта функция может использоваться для генерации случайных байтов.
Можно генерировать случайные числа, но что, если нужно генерировать случайные байты? Раньше разработчикам приходилось для этого проявлять изобретательность. Хотя можно использовать os.getrandom() , os.urandom() или secrets.token_bytes() , но нельзя генерировать псевдослучайные паттерны.
К примеру, чтобы гарантировать, что случайные числа генерируются с ожидаемым поведением и процесс воспроизводится, обычно используется модуль random.Random .
В результате был введен метод random.Random.randbytes() . Он также может генерировать случайные байты контролируемым способом.
Для получения более подробной информации вы можете ознакомиться с источником.
10. Исправление функции замены строки
Раньше «».replace(«», s, n) возвращал пустую строку вместо s для всех ненулевых n .
Этот баг сбивал с толку пользователей и приводил к нестабильному поведению приложений.
В Python 3.9 проблема была устранена, и теперь функция замены совместима с «».replace(«», s) .
Работает она следующим образом: для заданного максимального аргумента вхождения замены, набор символов из строки заменяется новым набором символов:
string.replace(s, old, new[, maxreplace])
В этом случае возвращается копия строки s со всеми вхождениями старой подстроки, замененной на новую. Если указан необязательный аргумент maxreplace, заменяются первые экземпляры maxreplace.
До этого функция replace имела непоследовательное поведение
В Python 3.9 также был исключен ряд избыточных функций, таких как Py_UNICODE_MATCH .
Если вы хотите узнать больше об этих улучшениях, прочтите официальное руководство здесь .
Нововведения в популярном языке программирования можно изучить самостоятельно, но придется потратить много времени и сил на поиск и систематизацию информации. Если ваш опыт в профессии еще не так велик, обратите внимание на факультет Python-разработки GeekBrains. Под руководством опытных преподавателей вы получите необходимые знания, а успешно завершившим обучение студентам онлайн-академия поможет с трудоустройством.