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

Новый релиз содержит улучшения в области исключений и обработки исключений в Python, новый модуль для обработки файлов TOML, улучшения для интерпретатора, новые типы и функции, а также объявляет устаревшими некоторые старые модули и API языка. Кроме того, тесты Python утверждают, что Python 3.11 на 10–60% быстрее, чем Python 3.10: вы можете увидеть результаты здесь.

Как установить и обновить

линукс

В Linux (в данном случае: Ubuntu) вы можете установить и обновить Python через локальный менеджер пакетов. Вы можете использовать deadsnakes PPA для установки самых последних версий Python.

sudo apt-get install software-properties-common
sudo add-apt-repository ppa:deadsnakes/ppa

После добавления репозитория вы можете установить Python 3.11 через apt:

sudo apt-get update
sudo apt-get install python3.11

macOS

В macOS я рекомендую использовать менеджер пакетов homebrew. Вы можете установить доморощенный через:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

После установки homebrew вы можете установить Python 3.11:

brew install [email protected]

Или, если вы уже установили более раннюю версию Python через homebrew (и обновили сам менеджер пакетов), обновите пакет Python до версии 3.11 с помощью этой команды:

brew upgrade python -v 3.11

Окна

В Windows у вас есть два способа обновить Python: через установщик Python или менеджер пакетов Chocolatey. Вы найдете установщик Python на официальной странице загрузки, и он проведет вас через весь процесс. Если вы хотите использовать менеджер пакетов Chocolatey, вы можете установить его через:

Set-ExecutionPolicy Bypass -Scope Process -Force; \
iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))

Затем вы можете использовать Chocolatey для установки Python 3.11 через командную строку:

choco install python -y --version 3.11

Или вы обновляете Python, если он уже установлен:

choco upgrade python -y --version 3.11

Группы исключений, кроме* и примечания

Теперь можно вызывать и обрабатывать несколько несвязанных исключений одновременно. Недавно введенный тип ExceptionGroup может объединять несвязанные исключения:

exceptions = ExceptionGroup(
    "all",
    [
        TypeError(1),
        ExceptionGroup("ex", [TypeError(2), ValueError(3)]),
        ExceptionGroup("os", [OSError(4)])
    ]
)

Эти пакеты дают красивые печатные иерархии:

import traceback
traceback.print_exception(exceptions)
| ExceptionGroup: all (3 sub-exceptions)
  +-+---------------- 1 ----------------
    | TypeError: 1
    +---------------- 2 ----------------
    | ExceptionGroup: ex (2 sub-exceptions)
    +-+---------------- 1 ----------------
      | TypeError: 2
      +---------------- 2 ----------------
      | ValueError: 3
      +------------------------------------
    +---------------- 3 ----------------
    | ExceptionGroup: os (1 sub-exception)
    +-+---------------- 1 ----------------
      | OSError: 4
      +------------------------------------

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

Python 3.11 представляет новое (или расширенное) ключевое слово для упрощения работы с ExceptionsGroups: except*. Символ * указывает, что можно обрабатывать несколько исключений:

try:
    ...
except* CustomError:
    ...
except* OSError as e:
    ...
except* (TypeError, ValueError) as e:
    ...

Описание PEP-0654 предоставляет дополнительную документацию для нового ключевого слова except*, например, рекурсивное сопоставление, вызов исключений в блоке исключений* или цепочка.

Базовый класс исключений BaseException также стал новым методом. Этот метод был добавлен, поскольку при перехвате и повторном возникновении исключений может быть добавлена ​​дополнительная информация.

add_note(note)

Добавьте строку note в примечания к исключению, которые отображаются в стандартной трассировке после строки исключения. TypeError возникает, если note не является строкой.

Добро пожаловать в новый модуль: tomllib

Tom’s Obvious Minimal Language (TOML) задуман как формат файла конфигурации, который является минимальным и легко читаемым. Синтаксис похож на INI-файлы, но он представляет собой фактический стандарт, в то время как INI имеет множество разновидностей. TOML поддерживает различные типы данных: String, Integer, Float, Boolean, Datetime, Array и Table. Поскольку он состоит из пар ключ-значение, его структура удобно анализируется в виде хэш-карты. Ниже приведен минимальный пример:

# this is a TOML config file example
title = "Config"
[general]
name = "Database"
created = 2022-11-26T08:30:00+02:00
[database]
  [database.connection]
  server = "192.168.1.1"
  ports = [ 8000, 8001, 8002 ]
  [database.auth]
  username = "root"
  password = "root"

Теперь Python 3.11 добавляет в стандартную библиотеку модуль для разбора файлов TOML под названием tomllib. К сожалению, на данный момент модуль поддерживает только синтаксический анализ файлов TOML, но не их запись. Предлагаются две альтернативы, если вам нужны возможности записи: пакет Tomli-W и пакет TOML Kit.

Однако, если вам просто нужно прочитать файл TOML, вы можете использовать новый модуль из стандартной библиотеки. Имейте в виду, что любой файл TOML должен быть открыт в двоичном режиме, чтобы tomllib мог правильно обрабатывать кодировку UTF-8 во всех системах. В следующем примере показано, как вы могли бы проанализировать наш пример файла TOML из приведенного выше:

import tomllib
with open("config.toml", "rb") as f:
    config = tomllib.load(f)
    server = config['database']['connection']['server']
    for port in config['database']['connection']['ports']:
        print(f'{server}:{port}')

Вы можете найти дополнительные советы и рекомендации по работе с модулем tomllib в статье RealPython, например, указав метод float для управления анализом и представлением чисел с плавающей запятой.

Улучшения интерпретатора

Python 3.11 догоняет возможности более современных компиляторов и теперь также будет указывать конкретное выражение, вызвавшее ошибку, а не просто указывать на строку:

Traceback (most recent call last):
  File "distance.py", line 11, in <module>
    print(manhattan_distance(p1, p2))
          ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "distance.py", line 6, in manhattan_distance
    return abs(point_1.x - point_2.x) + abs(point_1.y - point_2.y)
                           ^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'x'

Кроме того, есть новый параметр командной строки -P, который вместе с переменной среды с именем PYTHONSAFEPATH отключает автоматическое добавление потенциально небезопасных путей к sys.path. Это функция, которую можно интегрировать в среду непрерывной интеграции для обеспечения безопасности и переносимости.

-P

Не добавляйте потенциально небезопасный путь к sys.path:

python -m module командная строка: не добавляйте текущий рабочий каталог.

python script.py командная строка: не добавляйте каталог сценария. Если это символическая ссылка, разрешите символические ссылки.

Командные строки python -c code и python (REPL): не добавляйте пустую строку, которая означает текущий рабочий каталог.

См. также переменную окружения PYTHONSAFEPATH и параметры -E и -I (изолированные).

Дополнительные типы и особенности типов

В новой версии представлены новые функции набора текста. Они кратко показаны в следующих разделах.

Вариативные дженерики

В Python 3.5 уже появилось TypeVar для дженериков, параметризованных одним типом. В Python 3.11 появился TypeVarTuple, который позволяет параметризовать произвольное количество типов. Следующий пример взят из PEP-646 и показывает использование этой новой функции:

from typing import TypeVar, TypeVarTuple
DType = TypeVar('DType')
Shape = TypeVarTuple('Shape')
class Array(Generic[DType, *Shape]):
    def __abs__(self) -> Array[DType, *Shape]: ...
    def __add__(self, other: Array[DType, *Shape]) -> Array[DType, *Shape]: ...
from typing import NewType
Height = NewType('Height', int)
Width = NewType('Width', int)
x: Array[float, Height, Width] = Array()

Пометка отдельных элементов TypedDict как обязательных или необязательных

Теперь отдельные элементы в TypedDict могут быть отмечены, должны ли они присутствовать или нет. По умолчанию все поля по-прежнему обязательны для обратной совместимости. Однако есть также параметр total, для которого можно установить значение False: в этом случае все поля TypedDict по умолчанию не обязательны.

class Movie(TypedDict):
   title: str
   year: NotRequired[int]
m1: Movie = {"title": "Black Panther", "year": 2018}  # OK
m2: Movie = {"title": "Star Wars"}  # OK (year is not required)
m3: Movie = {"year": 2022}  # ERROR (missing required field title)

Собственный тип

PEP-673 вводит аннотацию Self для методов, которые возвращают экземпляр своего класса. В следующем примере показан вариант использования альтернативного конструктора:

class MyInt:
    @classmethod
    def fromhex(cls, s: str) -> Self:
        return cls(int(s, 16))

Произвольный литеральный строковый тип

Python 3.11 представляет новую аннотацию для дополнительной безопасности в отношении строк: LiteralString. Эта аннотация позволяет функциям принимать произвольные типы литеральных строк, а также строки, созданные из других литеральных строк. Вы можете установить требования к конфиденциальным функциям, например тем, которые выполняют операторы SQL для защиты от атак путем внедрения кода SQL.

В соответствии с PEP-675 показано, как эту аннотацию можно использовать для SQL-запросов:

def run_query(sql: LiteralString) -> ...
    ...
def caller(
    arbitrary_string: str,
    query_string: LiteralString,
    table_name: LiteralString,
) -> None:
    run_query("SELECT * FROM students")       # ok
    run_query(query_string)                   # ok
    run_query("SELECT * FROM " + table_name)  # ok
    run_query(arbitrary_string)               # type checker error
    run_query(                                # type checker error
        f"SELECT * FROM students WHERE name = {arbitrary_string}"
    )

Старое должно уйти: устаревание

Следующие устаревшие стандартные библиотечные модули объявлены устаревшими и будут удалены в Python 3.13:

  • aifc
  • chunk
  • msilib
  • pipes
  • telnetlib
  • audioop
  • crypt
  • nis
  • sndhdr
  • uu
  • cgi
  • imghdr
  • nntplib
  • spwd
  • xdrlib
  • cgitb
  • mailcap
  • ossaudiodev
  • sunau

Кроме того, модули asynchat, asyncore и smtpd (которые уже объявлены устаревшими) были обновлены, чтобы отметить, что они будут удалены в Python 3.12. Кроме того, пакет lib2to3 и инструмент 2to3 теперь устарели и, возможно, не смогут анализировать Python 3.10 или новее. Недокументированные модули sre_compile, sre_constants и sre_parse теперь также устарели.

API-интерфейсы кодировщика Py_UNICODE были удалены, потому что они уже устарели и больше не используются, поскольку есть лучшие и более эффективные альтернативы. Если вы все еще используете эти API, соответствующий PEP-624 предоставляет руководство по миграции.

Некоторые макросы были преобразованы в статические встроенные функции, чтобы избежать подводных камней макросов. Вы можете найти дополнительную информацию об этих макросах в соответствующем PEP-670.

Заключение

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

Решите для себя, стоит ли обновляться, но самое главное: продолжайте кодить и продолжайте творить!