Что нового в Python 3.8

Редактор:Раймонд Хиттингер

В этой статье объясняются новые функции Python 3.8 по сравнению с 3.7. Для получения полной информации см. журнал изменений.

Python 3.8 был выпущен 14 октября 2019 года.

Резюме — основные моменты релиза

Новые особенности

Выражения присвоения

Появился новый синтаксис :=, который присваивает значения переменным как часть более крупного выражения. Его ласково называют «моржовым оператором» из-за его сходства с глазами и клыками моржа.

В этом примере выражение присваивания помогает избежать двойного вызова len():

if (n := len(a)) > 10:
    print(f"List is too long ({n} elements, expected <= 10)")

Аналогичное преимущество возникает при сопоставлении регулярных выражений, когда объекты сопоставления необходимы дважды: один раз для проверки наличия совпадения, а другой — для извлечения подгруппы:

discount = 0.0
if (mo := re.search(r'(\d+)% discount', advertisement)):
    discount = float(mo.group(1)) / 100.0

Оператор также полезен с циклами while, которые вычисляют значение для проверки завершения цикла, а затем снова нуждаются в том же значении в теле цикла:

# Цикл на блоках фиксированной длины
while (block := f.read(256)) != '':
    process(block)

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

[clean_name.title() for name in names
 if (clean_name := normalize('NFC', name)) in allowed_names]

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

См. полное описание в PEP 572.

(Предоставлено Эмили Морхаус в bpo-35224.)

Только позиционные параметры

Существует новый синтаксис параметра функции /, указывающий, что некоторые параметры функции должны быть указаны позиционно и не могут использоваться в качестве ключевых аргументов. Это такое же обозначение, которое показано в help() для функций C, аннотированных с помощью инструмента Клиники споров Ларри Гастингса.

В следующем примере параметры a и b являются только позиционными, тогда как c или d могут быть позиционными или ключевыми, а e или f должны быть ключевыми:

def f(a, b, /, c, d, *, e, f):
    print(a, b, c, d, e, f)

Следующее — действительный вызов:

f(10, 20, 30, d=40, e=50, f=60)

Однако это недействительные вызовы:

f(10, b=20, c=30, d=40, e=50, f=60)   # b не может быть ключевым аргументом
f(10, 20, 30, 40, 50, f=60)           # e должен быть ключевым аргументом

Одним из вариантов использования этой нотации является то, что она позволяет чистым функциям Python полностью имитировать поведение существующих функций, закодированных на C. Например, встроенная функция divmod() не принимает ключевые аргументы:

def divmod(a, b, /):
    "Эмулирует встроенную функцию divmod() "
    return (a // b, a % b)

Другой вариант использования — исключить ключевые аргументы, когда имя параметра бесполезно. Например, у встроенной функции len() сигнатура len(obj, /). Это исключает неудобные вызовы, такие как:

len(obj='hello')  # Ключевой аргумент "obj" ухудшает читаемость

Ещё одно преимущество маркировки параметра как позиционного состоит в том, что это позволяет изменять имя параметра в будущем без риска нарушения клиентского кода. Например, в модуле statistics имя параметра dist может быть изменено в будущем. Это стало возможным благодаря следующей спецификации функции:

def quantiles(dist, /, *, n=4, method='exclusive')
    ...

Поскольку параметры слева от / не представлены в качестве возможных ключевых аргументов, имена параметров остаются доступными для использования в **kwargs:

>>> def f(a, b, /, **kwargs):
...     print(a, b, kwargs)
...
>>> f(10, 20, a=1, b=2, c=3)         # a и b используются двумя способами
10 20 {'a': 1, 'b': 2, 'c': 3}

Это значительно упрощает реализацию функций и методов, которым необходимо принимать произвольные ключевые аргументы. Например, вот отрывок из кода в модуле collections:

class Counter(dict):

    def __init__(self, iterable=None, /, **kwds):
        # Примечание. "iterable" является возможным ключевым аргументом

См. полное описание в PEP 570.

(Предоставлено Пабло Галиндо в bpo-36540.)

Кэш параллельной файловой системы для скомпилированных файлов байт-кода

Новый параметр PYTHONPYCACHEPREFIX (также доступный как -X pycache_prefix) настраивает неявный кэш байт-кода для использования отдельного параллельного дерева файловой системы, а не подкаталогов __pycache__ по умолчанию в каждом исходном каталоге.

Расположение кэша указано в sys.pycache_prefix (None указывает расположение по умолчанию в подкаталогах __pycache__).

(Предоставлено Карлом Мейером в bpo-33499.)

Сборка отладки использует тот же ABI, что и релизная сборка

Python теперь использует один и тот же ABI независимо от того, встроен ли он в режиме релиза или отладки. В Unix, когда Python построен в режиме отладки, теперь можно загружать расширения C, созданные в режиме релиза, и расширения C, созданные с использованием стабильного ABI.

Сборки релиза и сборки отладки теперь совместимы с ABI: определение макроса Py_DEBUG больше не подразумевает макрос Py_TRACE_REFS, который вводит единственную несовместимость ABI. Макрос Py_TRACE_REFS, который добавляет функцию sys.getobjects() и переменную среды PYTHONDUMPREFS, можно установить с помощью новой опции сборки ./configure --with-trace- refs. (Предоставлено Виктором Стиннером в bpo-36465.)

В Unix расширения C больше не связаны с libpython, за исключением Android и Cygwin. Теперь статически связанный Python может загружать расширение C, созданное с использованием общей библиотеки Python. (Предоставлено Виктором Стиннером в bpo-21536.)

В Unix, когда Python построен в режиме отладки, импорт теперь также ищет расширения C, скомпилированные в режиме релиза, и расширения C, скомпилированные с помощью стабильного ABI. (Предоставлено Виктором Стиннером в bpo-36722.)

Чтобы встроить Python в приложение, необходимо передать новый параметр --embed в python3-config --libs --embed, чтобы получить -lpython3.8 (связать приложение с libpython). Для поддержки версий 3.8 и более ранних версий сначала попробовать python3-config --libs --embed, а в случае сбоя предыдущей команды возвратиться к python3-config --libs (без --embed).

Добавлена модуль pkg-config python-3.8-embed для встраивания Python в приложение: pkg-config python-3.8-embed --libs включает -lpython3.8. Для поддержки версий 3.8 и более ранних версий сначала попробовать pkg-config python-X.Y-embed --libs, а в случае сбоя предыдущей команды возвратиться к pkg-config python-X.Y --libs (без --embed) (замените X.Y версией Python).

С другой стороны, pkg-config python3.8 --libs больше не содержит -lpython3.8. Расширения C не должны быть связаны с libpython (за исключением Android и Cygwin, чьи случаи обрабатываются сценарием); это изменение намеренно обратно несовместимо. (Предоставлено Виктором Стиннером в bpo-36721)

f-строки поддерживают = для самодокументирования выражений и отладки

Добавлен спецификатор = в f-строках. Строка f, например f'{expr=}', будет расширена до текста выражения, знака равенства, а затем до представления вычисленного выражения. Например:

>>> user = 'eric_idle'
>>> member_since = date(1975, 7, 31)
>>> f'{user=} {member_since=}'
"user='eric_idle' member_since=datetime.date(1975, 7, 31)"

Обычный спецификаторы формата f-строки позволяет больше контролировать отображения результата выражения:

>>> delta = date.today() - member_since
>>> f'{user=!s}  {delta.days=:,d}'
'user=eric_idle  delta.days=16,075'

Спецификатор = отобразит все выражение целиком, чтобы можно было показать вычисления:

>>> print(f'{theta=}  {cos(radians(theta))=:.3f}')
theta=30  cos(radians(theta))=0.866

(Предоставлено Эриком в. Смитом и Ларри Гастингсом в bpo-36817.)

PEP 578: Хуки аудита времени выполнения Python

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

См. PEP 578 для получения полной информации.

PEP 587: конфигурация инициализации Python

PEP 587 добавляет новый C API для настройки инициализации Python, обеспечивающий более точный контроль над всей конфигурацией и улучшенный отчёт об ошибках.

Новые конструкции:

Новые функции:

Этот PEP также добавляет к этим внутренним структурам поля _PyRuntimeState.preconfig (тип PyPreConfig) и PyInterpreterState.config (тип PyConfig). PyInterpreterState.config становится новой эталонной конфигурацией, заменяя глобальные переменные конфигурации и другие частные переменные.

См. документацию в Конфигурация инициализации Python.

См. полное описание в PEP 587.

(Предоставлено Виктором Стиннером в bpo-36763)

Vectorcall: протокол быстрого вызова для CPython

Протокол «vectorcall» добавлен в API Python/C. Он предназначен для формализации существующих оптимизаций, которые уже были сделаны для различных классов. Любой тип расширения, реализующий вызываемый объект, может использовать этот протокол.

В настоящее время это временно. Цель состоит в том, чтобы сделать его полностью общедоступным в Python 3.9.

См. полное описание PEP 590.

(Предоставлено Джеруном Демейером и Марком Шенноном в bpo-36974.)

Протокол Pickle 5 с внеполосными буферами данных

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

Протокол 5 pickle вводит поддержку внеполосных буферов, где PEP 3118-совместимые данные могут передаваться отдельно от основного потока pickle по усмотрению уровня связи.

См. полное описание в PEP 574.

(Предоставлено Антуаном Питру в bpo-36785.)

Другие языковые изменения

  • Оператор continue был недопустимым в предложении finally из-за проблемы с реализацией. В Python 3.8 это ограничение снято. (Предоставлено Сергеем Сторчакой в bpo-32489.)

  • Типы bool, int и fractions.Fraction теперь имеют метод as_integer_ratio(), аналогичный тому, который используется в float и decimal.Decimal. Это незначительное расширение API позволяет писать numerator, denominator = x.as_integer_ratio() и работать с несколькими числовыми типами. (Предоставлено Лизой Роуч в bpo-33073 и Раймондом Хеттингером в bpo-37819)

  • Конструкторы int, float и complex теперь будут использовать специальный метод __index__(), если он доступен, а соответствующий метод __int__(), __float__() или __complex__() недоступен. (Предоставлено Сергеем Сторчакой в bpo-20092.)

  • Добавлена поддержка экранирования \N{name} в регулярные выражения:

    >>> notice = 'Copyright © 2019'
    >>> copyright_year_pattern = re.compile(r'\N{copyright sign}\s*(\d{4})')
    >>> int(copyright_year_pattern.search(notice).group(1))
    2019
    

    (Предоставлено Джонатаном Юнис и Сергеем Сторчакой в bpo-30688.)

  • Dict и dictviews теперь можно повторять в обратном порядке вставки с использованием reversed(). (Предоставлено Реми Лапейром в bpo-33462.)

  • Синтаксис, разрешенный для имён ключевых аргументов в вызовах функций, был дополнительно ограничен. В частности, f((keyword)=arg) больше не разрешен. Он никогда не предназначался для разрешения большего, чем простое имя в левой части термина назначения ключевого аргумента. (Предоставлено Бенджамином Петерсоном в bpo-34641.)

  • Обобщенная итеративная распаковка в операторах yield и return больше не требует заключения в круглые скобки. Это приводит синтаксис yield и return в лучшее согласование с обычным синтаксисом присваивания:

    >>> def parse(family):
            lastname, *members = family.split()
            return lastname.upper(), *members
    
    >>> parse('simpsons homer marge bart lisa sally')
    ('SIMPSONS', 'homer', 'marge', 'bart', 'lisa', 'sally')
    

    (Предоставлено Дэвидом Катбертом и Джорданом Чепменом в bpo-32117.)

  • Если в коде, например [(10, 20) (30, 40)], отсутствует запятая, компилятор отображает SyntaxWarning с полезным предложением. Это лучше, чем просто наличие TypeError, указывающего, что первый кортеж не вызывается. (Предоставлено Сергеем Сторчакой в bpo-15248.)

  • Арифметические операции между подклассами объектов datetime.date или datetime.datetime и datetime.timedelta теперь возвращают экземпляр подкласса, а не базовый класс. Это также влияет на возвращаемый тип операций, реализация которых (прямо или косвенно) использует арифметику datetime.timedelta, например astimezone(). (Предоставлено Полом Гэнсслом в bpo-32417.)

  • Когда интерпретатор Python прерывается нажатием Ctrl-C (SIGINT) и результирующее исключение KeyboardInterrupt не перехвачено, процесс Python теперь завершается через сигнал SIGINT или с правильным кодом выхода, так что вызывающий процесс может обнаружить, что он умер из-за Ctrl-C. Оболочки в POSIX и Windows используют это для правильного завершения сценариев в интерактивных сеансах. (Предоставлено Google через Грегори П. Смита в bpo-1054041.)

  • Некоторые расширенные стили программирования требуют обновления объекта types.CodeType для существующей функции. Поскольку объекты кода неизменяемы, необходимо создать новый объект кода, который смоделирован на основе существующего объекта кода. С 19 параметрами это было несколько утомительно. Теперь новый метод replace() позволяет создать клон с несколькими измененными параметрами.

    Вот пример, который изменяет функцию statistics.mean(), чтобы предотвратить использование параметра data в качестве ключевого аргумента

    >>> from statistics import mean
    >>> mean(data=[10, 20, 90])
    40
    >>> mean.__code__ = mean.__code__.replace(co_posonlyargcount=1)
    >>> mean(data=[10, 20, 90])
    Traceback (most recent call last):
      ...
    TypeError: mean() got some positional-only arguments passed as keyword arguments: 'data'
    

    (Предоставлено Виктором Стиннером в bpo-37032.)

  • Для целых чисел форма с тремя аргументами функции pow() теперь позволяет показателю быть отрицательным в случае, когда основание является относительно простым по модулю. Затем она вычисляет модульную обратную величину, обратную основанию, когда показатель степени равен -1, и подходящую степень этого обратного значения для других отрицательных показателей степени. Например, чтобы вычислить модульную мультипликативную инверсию 38 по модулю 137:

    >>> pow(38, -1, 137)
    119
    >>> 119 * 38 % 137
    1
    

    Модульные инверсии возникают в решении линейных Диофантовых уравнений. Например, чтобы найти целочисленные решения для 4258𝑥 + 147𝑦 = 369, сначала перепишите как 4258𝑥 369 (mod 147), а затем решите:

    >>> x = 369 * pow(4258, -1, 147) % 147
    >>> y = (4258 * x - 369) // -147
    >>> 4258 * x + 147 * y
    369
    

    (Предоставлено Марком Дикинсоном в bpo-36027)

  • Понятия Dict были синхронизированы с литералами dict, так что сначала вычисляется ключ, а затем значение:

    >>> # словарное включение
    >>> cast = {input('role? '): input('actor? ') for i in range(2)}
    role? King Arthur
    actor? Chapman
    role? Black Knight
    actor? Cleese
    
    >>> # словарный литерал
    >>> cast = {input('role? '): input('actor? ')}
    role? Sir Robin
    actor? Eric Idle
    

    Гарантированный порядок выполнения полезен с выражениями присваивания, потому что переменные, назначенные в ключевом выражении, будут доступны в выражении значения:

    >>> names = ['Martin von Löwis', 'Łukasz Langa', 'Walter Dörwald']
    >>> {(n := normalize('NFC', name)).casefold() : n for name in names}
    {'martin von löwis': 'Martin von Löwis',
     'łukasz langa': 'Łukasz Langa',
     'walter dörwald': 'Walter Dörwald'}
    

    (Предоставлено Йорном Хейсслером в bpo-35224.)

  • Метод object.__reduce__() теперь может возвращать кортеж длиной от двух до шести элементов. Раньше пределом было пять. Новый необязательный шестой элемент вызывается с сигнатураю (obj, state). Это позволяет напрямую контролировать поведение определенного объекта при обновлении состояния. Если не None, этот вызываемый объект будет иметь приоритет над методом объекта __setstate__(). (Предоставлено Пьером Глейзером и Оливье Гризелем в bpo-35900.)

Новые модули

  • Новый модуль importlib.metadata обеспечивает (предварительную) поддержку чтения метаданных из сторонних пакетов. Например, он может извлекать номер версии установленного пакета, список точек входа и многое другое:

    >>> # Примечание. В следующем примере требуется, чтобы популярный "requires"
    >>> # пакет был установлен.
    >>>
    >>> from importlib.metadata import version, requires, files
    >>> version('requests')
    '2.22.0'
    >>> list(requires('requests'))
    ['chardet (<3.1.0,>=3.0.2)']
    >>> list(files('requests'))[:5]
    [PackagePath('requests-2.22.0.dist-info/INSTALLER'),
     PackagePath('requests-2.22.0.dist-info/LICENSE'),
     PackagePath('requests-2.22.0.dist-info/METADATA'),
     PackagePath('requests-2.22.0.dist-info/RECORD'),
     PackagePath('requests-2.22.0.dist-info/WHEEL')]
    

    (Предоставлено Барри Варшавой и Джейсоном р. Кумбсом в bpo-34632)

Улучшение модулей

ast

Узлы AST теперь имеют атрибуты end_lineno и end_col_offset, которые указывают точное местоположение конца узла. (Это относится только к узлам с атрибутами lineno и col_offset.)

Новая функция ast.get_source_segment() возвращает исходный код для определенного узла AST.

(Предоставлено Иваном Левковским в bpo-33416.)

Функция ast.parse() имеет несколько новых флагов:

  • type_comments=True заставляет его возвращать текст комментариев типа PEP 484 и PEP 526, связанных с определенными узлами AST;
  • mode='func_type' можно использовать для синтаксического анализа PEP 484 «комментариев типа сигнатуры» (возвращаемых для узлов AST определения функции);
  • feature_version=(3, N) позволяет указать более раннюю версию Python 3. Например, feature_version=(3, 4) будет рассматривать async и await как незарезервированные слова.

(Предоставлено Гвидо ван Россумом в bpo-35766.)

asyncio

asyncio.run() перешёл от временного API к стабильному. Функция может использоваться для выполнения корутину и возврата результата при автоматическом управлении циклом событий. Например:

import asyncio

async def main():
    await asyncio.sleep(0)
    return 42

asyncio.run(main())

Это приблизительно эквивалент:

import asyncio

async def main():
    await asyncio.sleep(0)
    return 42

loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
    loop.run_until_complete(main())
finally:
    asyncio.set_event_loop(None)
    loop.close()

Фактическая реализация значительно сложнее. Таким образом, asyncio.run() должен быть предпочтительным способом запуска asyncio программ.

(Предоставлено Юрием Селивановым в bpo-32314.)

Запуск python -m asyncio запускает асинхронный REPL. Это позволяет быстро экспериментировать с кодом верхнего уровня await. Больше нет необходимости напрямую вызывать asyncio.run(), который порождает новый цикл событий при каждом вызове:

$ python -m asyncio
asyncio REPL 3.8.0
Use "await" directly instead of "asyncio.run()".
Type "help", "copyright", "credits" or "license" for more information.
>>> import asyncio
>>> await asyncio.sleep(10, result='hello')
hello

(Предоставлено Юрием Селивановым в bpo-37028.)

Исключение asyncio.CancelledError теперь наследуется от BaseException, а не Exception, и больше не наследуется от concurrent.futures.CancelledError. (Предоставлено Юрием Селивановым в bpo-32528.)

В Windows цикл событий по умолчанию теперь ProactorEventLoop. (Предоставлено Виктором Стиннером в bpo-34687.)

ProactorEventLoop теперь также поддерживает UDP. (Предоставлено Адамом Мейли и Андреем Светловым в bpo-29883.)

ProactorEventLoop теперь может быть прерван KeyboardInterrupt («CTRL + C»). (Предоставлено Владимиром Матвеевым, номер bpo-23057.)

Добавлен asyncio.Task.get_coro() для получения обернутой корутины в asyncio.Task. (Предоставлено Алексом Грёнхольмом в bpo-36999.)

Задачи Asyncio теперь могут быть названы либо путём передачи ключевого аргумента name в asyncio.create_task() или методу цикла событий create_task(), либо путём вызова метода set_name() для объекта задачи. Имя задачи отображается в выводе repr() asyncio.Task, а также может быть получено с помощью метода get_name(). (Предоставлено Алексом Грёнхольмом в bpo-34270.)

Добавлена поддержка для Счастливых Глазных Яблок (happy eyeballs)asyncio.loop.create_connection(). Чтобы указать поведение, были добавлены два новых параметра: happy_eyeballs_delay и interleave. Алгоритм Happy Eyeballs улучшает скорость отклика в приложениях, поддерживающих IPv4 и IPv6, путем одновременного подключения с использованием обоих. (Предоставлено twisteroid ambassador в bpo-33530.)

builtins

Встроенная compile() была улучшена, чтобы принимать флаг ast.PyCF_ALLOW_TOP_LEVEL_AWAIT. После передачи этого нового флага compile() разрешит конструкции верхнего уровня await, async for и async with, которые обычно считаются недопустимым синтаксисом. Затем может быть возвращен асинхронный объект кода, помеченный флагом CO_COROUTINE. (Предоставлено Матиасом Бюссонье в bpo-34616)

collections

Метод _asdict() для collections.namedtuple() теперь возвращает dict вместо collections.OrderedDict. Это работает, потому что обычные dicts имеют гарантированный порядок, начиная с Python 3.7. Если требуются дополнительные функции OrderedDict, предлагаемое исправление — приведение результата к желаемому типу: OrderedDict(nt._asdict()). (Предоставлено Реймондом Хиттингером в bpo-35864)

cProfile

Класс cProfile.Profile теперь можно использовать в качестве менеджера контекста. Профилируемый блок кода, запустив:

import cProfile

with cProfile.Profile() as profiler:
      # код для профилирования
      ...

(Предоставлено Скоттом Сандерсоном в bpo-29235.)

csv

csv.DictReader теперь возвращает экземпляры dict вместо collections.OrderedDict. Инструмент теперь работает быстрее и использует меньше памяти, сохраняя при этом порядок полей. (Предоставлено Майклом Селиком в bpo-34003.)

curses

Добавлена новая переменная, содержащая структурированную информацию о версии для базовой библиотеки ncurses: ncurses_version. (Предоставлено Сергеем Сторчакой в bpo-31680.)

ctypes

В Windows CDLL и подклассы теперь принимают параметр winmode, чтобы указать флаги для основного вызова LoadLibraryEx. Флаги по умолчанию установлены для загрузки зависимостей DLL только из надежных расположений, включая путь, в котором хранится DLL (если для загрузки исходной DLL используется полный или частичный путь), и пути, добавленные add_dll_directory(). (Предоставлено Стивом Дауэром в bpo-36085.)

datetime

Добавлены новые альтернативные конструкторы datetime.date.fromisocalendar() и datetime.datetime.fromisocalendar(), которые создают объекты date и datetime соответственно из года ISO, номера недели и дня недели; это инверсия метода isocalendar каждого класса. (Предоставлено Полом Гэнсслом в bpo-36004.)

functools

functools.lru_cache() теперь можно использовать как прямой декоратор, а не как функцию, возвращающую декоратор. Итак, оба они теперь поддерживаются:

@lru_cache
def f(x):
    ...

@lru_cache(maxsize=256)
def f(x):
    ...

(Предоставлено Реймондом Хиттингером в bpo-36772.)

Добавлен новый декоратор functools.cached_property() для вычисляемых свойств, кэшированных на время существования экземпляра.

import functools
import statistics

class Dataset:
   def __init__(self, sequence_of_numbers):
      self.data = sequence_of_numbers

   @functools.cached_property
   def variance(self):
      return statistics.variance(self.data)

(Предоставлено Карлом Мейером в bpo-21145)

Добавлен новый декоратор functools.singledispatchmethod(), который преобразует методы в общие функции (дженерики), используя одиночную диспетчеризацию:

from functools import singledispatchmethod
from contextlib import suppress

class TaskManager:

    def __init__(self, tasks):
        self.tasks = list(tasks)

    @singledispatchmethod
    def discard(self, value):
        with suppress(ValueError):
            self.tasks.remove(value)

    @discard.register(list)
    def _(self, tasks):
        targets = set(tasks)
        self.tasks = [x for x in self.tasks if x not in targets]

(Предоставлено Итаном Смитом в bpo-32380)

gc

get_objects() теперь может получать необязательный параметр generation, указывающий поколение, из которого нужно получить объекты. (Предоставлено Пабло Галиндо в bpo-36016.)

gettext

Добавлен pgettext() и его варианты. (Предоставлено Францем Гласнером, Эриком Араужо и Шерил Сабелла в bpo-2504.)

gzip

Добавлен параметр mtime в gzip.compress() для воспроизводимого вывода. (Предоставлено Го Ци Тео в bpo-34898.)

Исключение BadGzipFile теперь вызывается вместо OSError для определенных типов недопустимых или поврежденных файлов gzip. (Предоставлено Филипом Грушчински, Мишель Орро и Закери Спитц в bpo-6584)

IDLE и idlelib

Вывод более N строк (по умолчанию 50) сжатых до кнопки. N можно изменить в разделе PyShell на странице «Общие» диалогового окна «Настройки». Меньшее количество, но, возможно, более длинных строк можно сжать, щелкнув правой кнопкой мыши на выходе. Сжатый вывод можно развозвращает на месте, дважды щелкнув кнопку, либо в буфер обмена, либо в отдельное окно, щелкнув кнопку правой кнопкой мыши. (Предоставлено Таль Эйнат в bpo-1529353.)

Добавлена «Выполнить индивидуально» в меню «Выполнить», чтобы запустить модуль с индивидуальными настройками. Любые введенные аргументы командной строки добавляются в sys.argv. Они также снова появятся в поле для следующего индивидуального запуска. Также можно подавить обычный перезапуск основного модуля Shell. (Предоставлено Шерил Сабелла, Терри Джен Риди и другими в bpo-5680 и bpo-37627.)

Добавлены дополнительные номера строк для окон редактора IDLE. Окна открываются без номеров строк, если иное не установлено на вкладке «Общие» диалогового окна конфигурации. Номера строк для существующего окна отображаются и скрываются в меню «Параметры». (Предоставлено Талом Эйнатом и Саймадхавом Хебликаром в bpo-17535.)

Собственная кодировка ОС теперь используется для преобразования между строками Python и объектами Tcl. Это позволяет IDLE работать с эмодзи и другими персонажами, не относящимися к BMP. Эти символы можно отображать, копировать и вставлять в буфер обмена или из него. Преобразование строк из Tcl в Python и обратно теперь никогда не дает сбоев. (Многие работали над этим восемь лет, но наконец проблема была решена Сергеем Сторчакой в bpo-13153.)

Новое в 3.8.1:

Добавлена возможность выключить мигание курсора. (Предоставлено Закери Спитцем в bpo-4603.)

Клавиша Escape теперь закрывает окна завершения IDLE. (Предоставлено Джонни Наджера в bpo-38944.)

Вышеуказанные изменения были перенесены в отладочные версии 3.7.

Добавлены ключевые слова в список завершения имени модуля. (Предоставлено Терри дж. Риди в bpo-37765.)

inspect

Функция inspect.getdoc() теперь может находить строки документации для __slots__, если этим атрибутом является dict, а значениями являются строки документации. Это предоставляет варианты документации, аналогичные тем, что у нас уже есть для property(), classmethod() и staticmethod():

class AudioClip:
    __slots__ = {'bit_rate': 'expressed in kilohertz to one decimal place',
                 'duration': 'in seconds, rounded up to an integer'}
    def __init__(self, bit_rate, duration):
        self.bit_rate = round(bit_rate / 1000.0, 1)
        self.duration = ceil(duration)

(Предоставлено Реймондом Хиттингером в bpo-36326.)

io

В режиме разработки (-X env) и в отладочной сборке финализатор io.IOBase теперь регистрирует исключение в случае сбоя метода close(). По умолчанию в сборке релиза исключение игнорируется без уведомления. (Предоставлено Виктором Стиннером в bpo-18748)

itertools

Функция itertools.accumulate() добавила опциональный ключевой аргумент initial для указания начального значения:

>>> from itertools import accumulate
>>> list(accumulate([10, 5, 30, 15], initial=1000))
[1000, 1010, 1015, 1045, 1060]

(Предоставлено Лизой Роуч в bpo-34659.)

json.tool

Добавлен параметр --json-lines, чтобы анализировать каждую строку ввода как отдельный объект JSON. (Предоставлено Вэй пэн Хун в bpo-31553.)

logging

Добавлен ключевой аргумент force в logging.basicConfig(). Если задано значение истина, все существующие обработчики, подключенные к корневому регистратору, удаляются и закрываются перед выполнением конфигурации, указанной другими аргументами.

Это решает давнюю проблему. После вызова регистратора или basicConfig() последующие вызовы basicConfig() игнорировались. Это затрудняло обновление, экспериментирование или обучение различным параметрам конфигурации ведения журнала с помощью интерактивной подсказки или записной книжки Jupyter.

(Предложено Реймондом Хиттингером, реализовано Донг-хи На и рассмотрено Винаем Саджипом в bpo-33897.)

math

Добавлена новая функция math.dist() для вычисления Евклидова расстояния между двумя точками. (Предоставлено Реймондом Хиттингером в bpo-33089.)

Расширена функция math.hypot() для обработки нескольких измерений. Раньше он поддерживал только двумерный случай. (Предоставлено Реймондом Хиттингером в bpo-33089.)

Добавлена новая функция math.prod(), аналогичная функции sum(), которая возвращает произведение «начального» значения (по умолчанию: 1) на итерацию чисел:

>>> prior = 0.8
>>> likelihoods = [0.625, 0.84, 0.30]
>>> math.prod(likelihoods, start=prior)
0.126

(Предоставлено Пабло Галиндо в bpo-35606.)

Добавлены две новые комбинаторные функции math.perm() и math.comb():

>>> math.perm(10, 3)    # Перестановки 10 вещей, взятых по 3 за раз
720
>>> math.comb(10, 3)    # Комбинации из 10 вещей, взятых по 3 за раз
120

(Предоставлено Яшем Аггарвалом, Келлер Фукс, Сергеем Сторчакой и Реймондом Хиттингером в bpo-37128, bpo-37178 и bpo-35431.)

Добавлена новая функция math.isqrt() для вычисления точных целочисленных квадратных корней без преобразования в числа с плавающей запятой. Новая функция поддерживает сколь угодно большие целые числа. Он быстрее, чем floor(sqrt(n)), но медленнее, чем math.sqrt():

>>> r = 650320427
>>> s = r ** 2
>>> isqrt(s - 1)         # правильно
650320426
>>> floor(sqrt(s - 1))   # неправильно
650320427

(Предоставлено Марком Дикинсоном в bpo-36887.)

Функция math.factorial() больше не принимает аргументы, не похожие на int. (Предоставлено Пабло Галиндо в bpo-33083.)

mmap

Класс mmap.mmap теперь имеет метод madvise() для доступа к системному вызову madvise(). (Предоставлено Закери Спитцем в bpo-32941.)

multiprocessing

Добавлен новый модуль multiprocessing.shared_memory. (Предоставлено Дэвином Поттсом в bpo-35813.)

В macOS по умолчанию теперь используется метод запуска spawn. (Предоставлено Виктором Стиннером в bpo-33725.)

os

Добавлена новая функция add_dll_directory() в Windows для предоставления дополнительных путей поиска для собственных зависимостей при импорте модулей расширения или загрузке библиотек DLL с помощью ctypes. (Предоставлено Стивом Дауэром в bpo-36085.)

Добавлена новая функция os.memfd_create() для обертывания системного вызова memfd_create(). (Предоставлено Закери Спитцем и Кристианом Хеймсом в bpo-26836)

В Windows большая часть ручной логики для обработки точек повторной обработки (включая символические ссылки и соединения каталогов) делегирована операционной системе. В частности, os.stat() теперь будет проходить через все, что поддерживается операционной системой, тогда как os.lstat() будет открывать только точки повторной обработки, которые идентифицируются как «суррогаты имени», в то время как другие открываются как для os.stat(). Во всех случаях stat_result.st_mode будет иметь только S_IFLNK, установленный для символических ссылок, а не другие виды точек повторной обработки. Чтобы определить другие виды точек повторной обработки, проверить новый атрибут stat_result.st_reparse_tag.

В Windows os.readlink() теперь может читать соединения каталогов. Обратите внимание, что islink() вернет False для соединений каталогов, и поэтому код, сначала проверяющий islink, будет продолжать обрабатывать соединения как каталоги, в то время как код, обрабатывающий ошибки от os.readlink(), теперь может обрабатывать соединения как ссылки.

(Предоставлено Стивом Дауэром в bpo-37834.)

os.path

Возвращающие логический результат функции os.path, например exists(), lexists(), isdir(), isfile(), islink() и ismount(), теперь возвращают False вместо того, чтобы вызывать ValueError или его подклассы UnicodeEncodeError и UnicodeDecodeError на уровне символов, не представляющих пути, содержащие символы. (Предоставлено Сергеем Сторчакой, bpo-33721.)

expanduser() в Windows теперь предпочитает переменную среды USERPROFILE и не использует HOME, который обычно не устанавливается для обычных учетных записей пользователей. (Предоставлено Энтони Соттилем в bpo-36264.)

isdir() в Windows больше не возвращает True для ссылки на несуществующий каталог.

realpath() в Windows теперь разрешает точки повторной обработки, включая символические ссылки и соединения каталогов.

(Предоставлено Стивом Дауэром в bpo-37834.)

pathlib

Методы pathlib.Path, которые возвращают логический результат, например exists(), is_dir(), is_file(), is_mount(), is_symlink(), is_block_device(), is_char_device(), is_fifo(), is_socket(), теперь возвращают False вместо вызова ValueError или соответствующие подклассу UnicodeEncodeError, на уровне ОС. (Предоставлено Сергеем Сторчакой в bpo-33721.)

Добавлен pathlib.Path.link_to(), который создает жесткую ссылку, указывающую на путь. (Предоставлено Джоанной Нанджекье в bpo-26978)

pickle

Расширения pickle, являющиеся подклассом оптимизированного для C Pickler, теперь могут отменять логику пиклинга функций и классов, определяя специальный метод reducer_override(). (Предоставлено Пьером Глейзером и Оливье Гризелем в bpo-35900.)

plistlib

Добавлен новый plistlib.UID и включена поддержка чтения и записи двоичных списков в кодировке NSKeyedArchiver. (Предоставлено Джоном Янзеном в bpo-26707.)

pprint

Модуль pprint добавил параметр sort_dicts к нескольким функциям. По умолчанию эти функции продолжают сортировку словарей перед отрисовкой или печатью. Однако, если для sort_dicts задано значение ложь, словари сохраняют порядок вставки ключей. Это может быть полезно для сравнения с входными данными JSON во время отладки.

Кроме того, есть удобная новая функция pprint.pp(), которая похожа на pprint.pprint(), но для sort_dicts по умолчанию используется значение False:

>>> from pprint import pprint, pp
>>> d = dict(source='input.txt', operation='filter', destination='output.txt')
>>> pp(d, width=40)                  # Первоначальный порядок
{'source': 'input.txt',
 'operation': 'filter',
 'destination': 'output.txt'}
>>> pprint(d, width=40)              # Ключи отсортированы в алфавитном порядке
{'destination': 'output.txt',
 'operation': 'filter',
 'source': 'input.txt'}

(Предоставлено Реми Лапейром в bpo-30670.)

py_compile

py_compile.compile() теперь поддерживает беззвучный режим. (Предоставлено Джоанной Нанджекье в bpo-22640.)

shlex

Новая функция shlex.join() действует как обратная shlex.split(). (Предоставлено Бо Бэйлсом в bpo-32102.)

shutil

shutil.copytree() теперь принимает новый ключевой аргумент dirs_exist_ok. (Предоставлено Джошем Бронсоном в bpo-20849.)

shutil.make_archive() теперь по умолчанию использует современный формат pax (POSIX.1-2001) для новых архивов, чтобы улучшить переносимость и соответствие стандартам, унаследованный от соответствующего изменения в модуле tarfile. (Предоставлено С. А. М. Герлахом в bpo-30661.)

shutil.rmtree() в Windows теперь удаляет соединения каталогов без предварительного рекурсивного удаления их содержимого. (Предоставлено Стивом Дауэром в bpo-37834.)

socket

Добавлены удобные функции create_server() и has_dualstack_ipv6() для автоматизации необходимых задач, обычно выполняемых при создании сокета сервера, включая прием соединений IPv4 и IPv6 на одном сокете. (Предоставлено Джампаоло Родола в bpo-17561.)

Функции socket.if_nameindex(), socket.if_nametoindex() и socket.if_indextoname() были реализованы в Windows. (Предоставлено Закери Спитцем в bpo-37007.)

ssl

Добавлен post_handshake_auth для включения и verify_client_post_handshake() для инициирования аутентификации после установления связи TLS 1.3. (Предоставлено Кристианом Хеймсом в bpo-34670.)

statistics

Добавлен statistics.fmean() как более быстрый вариант statistics.mean() с плавающей запятой. (Предоставлено Реймондом Хиттингером и Стивеном д’Апрано в bpo-35904.)

Добавлен statistics.geometric_mean() (предоставлен Реймондом Хиттингером в bpo-27181.)

Добавлен statistics.multimode(), который возвращает список наиболее распространенных значений. (Предоставлено Реймондом Хиттингером в bpo-35892)

Добавлен statistics.quantiles(), который делит данные или распределение на равновероятные интервалы (например, квартили, децили или процентили). (Предоставлено Реймондом Хиттингером в bpo-36546.)

Добавлен statistics.NormalDist, инструмент для создания и управления нормальным распределением случайной величины. (Предоставлено Реймондом Хиттингером в bpo-36018.)

>>> temperature_feb = NormalDist.from_samples([4, 12, -3, 2, 7, 14])
>>> temperature_feb.mean
6.0
>>> temperature_feb.stdev
6.356099432828281

>>> temperature_feb.cdf(3)            # Вероятность ниже 3 градусов
0.3184678262814532
>>> # Относительная вероятность быть 7 градусов против 10 градусов
>>> temperature_feb.pdf(7) / temperature_feb.pdf(10)
1.2039930378537762

>>> el_niño = NormalDist(4, 2.5)
>>> temperature_feb += el_niño        # Добавим к этому климатический эффект
>>> temperature_feb
NormalDist(mu=10.0, sigma=6.830080526611674)

>>> temperature_feb * (9/5) + 32      # Переводим в градусы Фаренгейта
NormalDist(mu=50.0, sigma=12.294144947901014)
>>> temperature_feb.samples(3)        # Генерируем случайные выборки
[7.672102882379219, 12.000027119750287, 4.647488369766392]

sys

Добавлена новая функция sys.unraisablehook(), которую можно переопределить, чтобы управлять обработкой «невыполнимых исключений». Он вызывается, когда возникает исключение, но Python не может его обработать. Например, когда деструктор вызывает исключение или во время сборки мусора (gc.collect()). (Предоставлено Виктором Стиннером в bpo-36829.)

tarfile

Модуль tarfile теперь по умолчанию использует современный формат pax (POSIX.1-2001) для новых архивов, а не предыдущий, специфичный для GNU. Это улучшает кроссплатформенную переносимость за счёт согласованной кодировки (UTF-8) в стандартизированном и расширяемом формате, а также предлагает ряд других преимуществ. (Предоставлено С. А. М. Герлахом в bpo-36268.)

threading

Добавлена новая функция threading.excepthook(), которая обрабатывает неперехваченное исключение threading.Thread.run(). Его можно переопределить, чтобы управлять обработкой неперехваченных исключений threading.Thread.run(). (Предоставлено Виктором Стиннером в bpo-1230540.)

Добавлена новая функция threading.get_native_id() и атрибут native_id в класс threading.Thread. Они возвращают собственный интегральный идентификатор потока текущего потока, назначенного ядром. Функция доступна только на определенных платформах, дополнительную информацию см. в get_native_id. (Предоставлено Джейком Теслером в bpo-36084.)

tokenize

Модуль tokenize теперь неявно испускает токен NEWLINE при вводе, не имеющем завершающей новой строки. Это поведение теперь соответствует тому, что делает внутри C-токенизатор. (Предоставлено Аммаром Аскаром в bpo-33899)

tkinter

Добавлены методы selection_from(), selection_present(), selection_range() и selection_to() в класс tkinter.Spinbox. (Предоставлено Жюльетт Монсель в bpo-34829.)

Добавлен метод moveto() в класс tkinter.Canvas. (Предоставлено Жюльетт Монсель в bpo-23831.)

Класс tkinter.PhotoImage теперь имеет методы transparency_get() и transparency_set(). (Предоставлено Закери Спитцем в bpo-25451.)

time

Добавлены новые часы CLOCK_UPTIME_RAW для macOS 10.12. (Предоставлено Джоанной Нанджекье в bpo-35702.)

typing

Модуль typing включает несколько новых функций:

  • Тип словаря с типами для каждого ключа. См. PEP 589 и typing.TypedDict. TypedDict использует только строковые ключи. По умолчанию требуется наличие каждого ключа. Укажите total=False, чтобы ключи были необязательными:

    class Location(TypedDict, total=False):
        lat_long: tuple
        grid_square: str
        xy_coordinate: tuple
    
  • Буквальные типы. См. PEP 586 и typing.Literal. Типы литералов указывают, что параметр или возвращаемое значение ограничено одним или несколькими значениями литерала:

    def get_status(port: int) -> Literal['connected', 'disconnected']:
        ...
    
  • «Заключительные» переменные, функции, методы и классы. См. PEP 591, typing.Final и typing.final(). Последний квалификатор инструктирует средство проверки статического типа ограничить создание подклассов, переопределение или переназначение:

    pi: Final[float] = 3.1415926536
    
  • Определения протокола. См. PEP 544, typing.Protocol и typing.runtime_checkable(). Простые ABC, например typing.SupportsInt, теперь являются подклассами Protocol.

  • Новый класс протокола typing.SupportsIndex.

  • Новые функции typing.get_origin() и typing.get_args().

unicodedata

Модуль unicodedata был обновлен для использования версии Юникод 12.1.0.

Новую функцию is_normalized() можно использовать для проверки того, что строка находится в определенной нормальной форме, часто намного быстрее, чем путем фактической нормализации строки. (Предоставлено Максом Белэнджером, Дэвидом Эурести и Грегом Прайсом в bpo-32285 и bpo-37966).

unittest

Добавлен AsyncMock для поддержки асинхронной версии Mock. Также были добавлены соответствующие новые функции assert для тестирования. (Предоставлено Лизой Роуч в bpo-26467).

В unittest добавлены addModuleCleanup() и addClassCleanup() для поддержки очистки для setUpModule() и setUpClass(). (Предоставлено Лизой Роуч в bpo-24412.)

Некоторые имитирующие функции assert теперь также выводят список фактических вызовов в случае сбоя. (Предоставлено Петтером Страндмарком в bpo-35047.)

Модуль unittest получил поддержку корутин, которые будут использоваться в качестве тестовых примеров с unittest.IsolatedAsyncioTestCase. (Предоставлено Андреем Светловым в bpo-32972.)

Пример:

import unittest


class TestRequest(unittest.IsolatedAsyncioTestCase):

    async def asyncSetUp(self):
        self.connection = await AsyncConnection()

    async def test_get(self):
        response = await self.connection.get("https://example.com")
        self.assertEqual(response.status_code, 200)

    async def asyncTearDown(self):
        await self.connection.close()


if __name__ == "__main__":
    unittest.main()

Venv

venv теперь включает сценарий Activate.ps1 на всех платформах для активации виртуальных сред в PowerShell Core 6.1. (Предоставлено Бреттом Кэнноном в bpo-32718)

weakref

Прокси-объекты, возвращаемые weakref.proxy(), теперь поддерживают операторы матричного умножения @ и @= в дополнение к другим числовым операторам. (Предоставлено Марком Дикинсоном в bpo-36669.)

xml

В качестве защиты от DTD и извлечения внешних объектов модули xml.dom.minidom и xml.sax больше не обрабатывают внешние объекты по умолчанию. (Предоставлено Кристианом Хеймсом в bpo-17239.)

Методы .find*() в модуле xml.etree.ElementTree поддерживают поиск с использованием подстановочных знаков, например {*}tag, игнорирующий пространство имён, и {namespace}*, возвращающий все теги в данном пространстве имён. (Предоставлено Стефаном Бенелем в bpo-28238.)

Модуль xml.etree.ElementTree предоставляет новую функцию –xml.etree.ElementTree.canonicalize(), которая реализует C14N 2.0. (Предоставлено Стефаном Бенелем в bpo-13611.)

Целевой объект xml.etree.ElementTree.XMLParser может получать события объявления пространства имён с помощью новых методов обратного вызова start_ns() и end_ns(). Кроме того, цель xml.etree.ElementTree.TreeBuilder может быть настроена для обработки событий, связанных с комментариями, и операторами по обработке, чтобы включить их в сгенерированное дерево. (Предоставлено Стефаном Бенелем в bpo-36676 и bpo-36673.)

xmlrpc

xmlrpc.client.ServerProxy теперь поддерживает необязательный ключевой аргумент headers для последовательности заголовков HTTP, отправляемых с каждым запросом. Среди прочего, это позволяет перейти с базовой аутентификации по умолчанию на более быструю сессионную аутентификацию. (Предоставлено Седриком Криером в bpo-35153.)

Оптимизация

  • Модуль subprocess теперь может использовать функцию os.posix_spawn() в некоторых случаях для повышения производительности. В настоящее время он используется только в macOS и Linux (с использованием glibc 2.24 или новее), если выполняются все эти Условия:

    • close_fds — Ложь;
    • Параметры preexec_fn, pass_fds, cwd и start_new_session не заданы;
    • путь executable содержит каталог.

    (Предоставлено Джоанной Нанджеки и Виктором Стиннером в bpo-35537.)

  • shutil.copyfile(), shutil.copy(), shutil.copy2(), shutil.copytree() и shutil.move() используют системные вызовы быстрого копирования для платформ в Linux и macOS для более эффективного копирования файла. «быстрое копирование» означает, что операция копирования происходит внутри ядра, избегая использования буферов пользовательского пространства в Python, как в «outfd.write(infd.read())». В Windows shutil.copyfile() использует больший размер буфера по умолчанию (1 МиБ вместо 16 КиБ) и вариант shutil.copyfileobj() на основе memoryview(). Ускорение копирования файла размером 512 МБ в одном разделе составляет около +26% в Linux, +50% в macOS и +40% в Windows. Кроме того, потребляется гораздо меньше циклов процессора. См. раздел Операции эффективного копирования, зависящие от платформы. (Предоставлено Джампаоло Родола в bpo-33671.)

  • shutil.copytree() использует функцию os.scandir(), и все функции копирования, зависящие от нее, используют кэшированные значения os.stat(). Ускорение копирования каталога с 8000 файлами составляет около +9% для Linux, +20% для Windows и +30% для общего ресурса Windows SMB. Также количество системных вызовов os.stat() уменьшено на 38%, что делает shutil.copytree() особенно быстрым в сетевых файловых системах. (Предоставлено Джампаоло Родола в bpo-33695.)

  • Протоколом по умолчанию в модуле pickle теперь является протокол 4, впервые представленный в Python 3.4. Он предлагает лучшую производительность и меньший размер по сравнению с Протоколом 3, доступным с Python 3.0.

  • Удален один член Py_ssize_t из PyGC_Head. Размер всех отслеживаемых GC объектов (например, кортежа, списка, dict) уменьшается на 4 или 8 байтов. (Предоставлено Инадой Наоки в bpo-33597)

  • uuid.UUID теперь использует __slots__, чтобы уменьшить объем памяти. (Предоставлено Воутером Болстерли и Талом Эйнатом в bpo-30977)

  • Повышена производительность operator.itemgetter() на 33%. Оптимизирована обработка аргументов и добавлен быстрый путь для общего случая одного неотрицательного целочисленного индекса в кортеж (что является типичным вариантом использования в стандартной библиотеке). (Предоставлено Раймондом Хеттингером в bpo-35664.)

  • Ускоренный поиск полей в collections.namedtuple(). Теперь они работают более чем в два раза быстрее, что делает их самой быстрой формой поиска переменных экземпляра в Python. (Предоставлено Раймондом Хеттингером, Пабло Галиндо и Джо Евником, Сергеем Сторчакой в bpo-32492.)

  • Конструктор list не увеличивает доступность внутреннего буфера элементов, если итерируемый вход имеет известную длину (входной элемент реализует __len__). Это делает созданный список в среднем на 12% меньше. (Предоставлено Раймондом Хеттингером и Пабло Галиндо в bpo-33234.)

  • В два раза увеличена скорость записи переменных класса. При обновлении атрибута, не связанного с опасностью, произошел ненужный вызов для обновления слотов. (Предоставлено Стефаном Бенелем, Пабло Галиндо Сальгадо, Раймондом Хеттингером, Нилом Шеменауэром и Сергеем Сторчакой в bpo-36012.)

  • Уменьшены накладные расходы на преобразование аргументов, передаваемых многим встроенным функциям и методам. Это ускорило вызов некоторых простых встроенных функций и методов до 20-50%. (Предоставлено Сергеем Сторчакой в bpo-23867, bpo-35582 и bpo-36127.)

  • В инструкции LOAD_GLOBAL теперь используется новый механизм «кэширования кода операции». Теперь это примерно на 40% быстрее. (Предоставлено Юрием Селивановым и Инадой Наоки, bpo-26219.)

Изменения в сборке и C API

  • По умолчанию sys.abiflags стал пустой строкой: флаг m для pymalloc стал бесполезным (сборки с pymalloc и без него совместимы с ABI) и поэтому был удален. (Предоставлено Виктором Стиннером в bpo-36707)

    Пример изменений:

    • Установлена только программа python3.8, программа python3.8m пропала.
    • Установлен только скрипт python3.8-config, скрипт python3.8m-config пропал.
    • Флаг m был удален из суффикса имён файлов динамической библиотеки: модули расширения в стандартной библиотеке, а также модули, созданные и устанавливаемые сторонними пакетами, например, загруженные из PyPI. В Linux, например, суффикс Python 3.7 .cpython-37m-x86_64-linux-gnu.so превратился в .cpython-38-x86_64-linux-gnu.so в Python 3.8.
  • Файлы заголовков были реорганизованы, чтобы лучше разделить различные типы API:

    • Include/*.h должен быть переносимым общедоступным стабильным C API.
    • Include/cpython/*.h должен быть нестабильным C API, специфичным для CPython; общедоступный API с некоторым частным API с префиксом _Py или _PY.
    • Include/internal/*.h — это частный внутренний C API, очень специфичный для CPython. Этот API не имеет гарантии обратной совместимости и не должен использоваться за пределами CPython. Он предоставляется только для очень специфических потребностей, таких как отладчики и профили, которые должны иметь доступ к внутренним компонентам CPython без вызова функций. Этот API теперь установлен make install.

    (Предоставлено Виктором Стиннером в bpo-35134 и bpo-35081, работа инициирована Эриком Сноу в Python 3.7.)

  • Некоторые макросы были преобразованы в статические встроенные функции: типы параметров и возвращаемый тип четко определены, у них нет проблем, специфичных для макросов, переменные имеют локальную область видимости. Примеры:

    (Предоставлено Виктором Стиннером в bpo-35059)

  • Функции PyByteArray_Init() и PyByteArray_Fini() были удалены. Они ничего не делали, начиная с Python 2.7.4 и Python 3.2.0, были исключены из ограниченного API (стабильный ABI) и не были задокументированы. (Предоставлено Виктором Стиннером в bpo-35713)

  • Результат PyExceptionClass_Name() теперь имеет тип const char *, а не char *. (Предоставлено Сергеем Сторчакой в bpo-33818.)

  • Удалена двойственность Modules/Setup.dist и Modules/Setup. Раньше при обновлении дерева исходных кодов CPython приходилось вручную копировать Modules/Setup.dist (внутри исходного дерева) в Modules/Setup (внутри дерева сборки), чтобы отразить любые изменения в восходящем направлении. Это было небольшим преимуществом для упаковщиков за счет частого раздражения разработчиков после разработки CPython, т. к. пропуск копирования файла могло привести к сбоям сборки.

    Теперь система сборки всегда читает из Modules/Setup внутри исходного дерева. Людям, которые хотят настроить этот файл, рекомендуется сохранять свои изменения в git-форке CPython или в виде файлов исправлений, как они бы поступили с любыми другими изменениями в исходном дереве.

    (Предоставлено Антуаном Питру в bpo-32430.)

  • Функции, которые преобразуют число Python в целое число C, например PyLong_AsLong(), и функции синтаксического анализа аргументов, такие как PyArg_ParseTuple() с единицами формата целочисленного преобразования, например 'i', теперь будут использовать специальный метод __index__() вместо __int__(), если он доступен. Предупреждение об устаревании будет выдано для объектов с методом __int__(), но без метода __index__() (например, Decimal и Fraction). PyNumber_Check() теперь будет возвращать 1 для объектов, реализующих __index__(). PyNumber_Long(), PyNumber_Float() и PyFloat_AsDouble() теперь также используют метод __index__(), если он доступен. (Предоставлено Сергеем Сторчакой в bpo-36048 и bpo-20092.)

  • Объекты типа, размещенные в куче, теперь будут увеличивать счетчик ссылок в PyObject_Init() (и его параллельном макросе PyObject_INIT) вместо PyType_GenericAlloc(). Типы, которые изменяют выделение или освобождение экземпляров, могут нуждаться в корректировке. (Предоставлено Эдди Элизондо в bpo-35810.)

  • Новая функция PyCode_NewWithPosOnlyArgs() позволяет создавать объекты кода, такие как PyCode_New(), но с дополнительным параметром posonlyargcount для указания количества позиционных аргументов. (Предоставлено Пабло Галиндо в bpo-37221.)

  • Py_SetPath() теперь устанавливает sys.executable на полный путь к программе (Py_GetProgramFullPath()), а не на имя программы (Py_GetProgramName()). (Предоставлено Виктором Стиннером в bpo-38234)

Устарело

Удаление API и функций

Следующие функции и API были удалены из Python 3.8:

  • Начиная с Python 3.3, импорт ABC из collections устарел, и импорт должен выполняться из collections.abc. Возможность импорта из коллекций была помечена для удаления в 3.8, но была отложена до 3.9. (См. bpo-36952.)
  • Модуль macpath, устаревший в Python 3.7, был удален. (Предоставлено Виктором Стиннером в bpo-35471.)
  • Функция platform.popen() была удалена после того, как она устарела с Python 3.3: вместо нее использовать os.popen(). (Предоставлено Виктором Стиннером в bpo-35345)
  • Функция time.clock() была удалена после того, как она устарела с Python 3.3: вместо этого использовать time.perf_counter() или time.process_time(), в зависимости от ваших требований, чтобы иметь четко определенное поведение. (Предоставлено Матиасом Бюссонье в bpo-36895.)
  • Сценарий pyvenv был удален в пользу python3.8 -m venv, чтобы избежать путаницы в отношении того, к какому интерпретатору Python привязан сценарий pyvenv. (Предоставлено Бреттом Кэнноном в bpo-25427.)
  • parse_qs, parse_qsl и escape удалены из модуля cgi. Они устарели в Python 3.2 и старше. Вместо этого они должны быть импортированы из модулей urllib.parse и html.
  • Функция filemode удалена из модуля tarfile. Он не документирован и не рекомендуется, начиная с Python 3.3.
  • Конструктор XMLParser больше не принимает аргумент html. Это никогда не оказывало эффекта и устарело в Python 3.4. Все остальные параметры теперь только ключевые. (Предоставлено Сергеем Сторчакой в bpo-29209.)
  • Удален метод doctype() из XMLParser. (Предоставлено Сергеем Сторчакой в bpo-29209.)
  • Кодек unicode_internal удален. (Предоставлено Инадой Наоки в bpo-36297.)
  • Объекты Cache и Statement модуля sqlite3 не доступны пользователю. (Предоставлено Авивом Паливодой в bpo-30262)
  • Ключевой аргумент bufsize для fileinput.input() и fileinput.FileInput(), который был проигнорирован и объявлен устаревшим, т. к. Python 3.6 был удален. bpo-36952 (Предоставлено Матиасом Бюссонье)
  • Функции sys.set_coroutine_wrapper() и sys.get_coroutine_wrapper(), устаревшие в Python 3.7, были удалены; bpo-36933 (Предоставлено Матиасом Бюссонье)

Переход на Python 3.8

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

Изменения в поведении Python

  • Выражения yield (как предложения yield, так и yield from) теперь запрещены в интерпретациях и выражениях генератора (кроме итерируемого выражения в крайнем левом предложении for). (Предоставлено Сергеем Сторчакой, bpo-10544.)
  • Компилятор теперь вызывает SyntaxWarning, когда проверки (is и is not) используются с определенными типами литералов (например, строки, числа). Часто они могут случайно сработать в CPython, но не гарантируются спецификацией языка. Предупреждение рекомендует пользователям вместо этого использовать тесты на равенство (== и !=). (Предоставлено Сергеем Сторчакой в bpo-34850.)
  • Интерпретатор CPython может принимать исключения в некоторых случаях. В Python 3.8 это происходит в меньшем количестве случаев. В частности, исключения, возникающие при получении атрибута из словаря типов, больше не игнорируются. (Предоставлено Сергеем Сторчакой, bpo-35459.)
  • Удалены реализации __str__ из встроенных типов bool, int, float, complex и нескольких классов из стандартной библиотеки. Теперь они наследуют __str__() от object. В результате определение метода __repr__() в подклассе этих классов повлияет на их строковое представление. (Предоставлено Сергеем Сторчакой в bpo-36793.)
  • В AIX sys.platform больше не содержит основную версию. Это всегда 'aix', а не 'aix3' .. 'aix7'. Поскольку более старые версии Python включают номер версии, рекомендуется всегда использовать sys.platform.startswith('aix'). (Предоставлено М. Фелтом в bpo-36588.)
  • PyEval_AcquireLock() и PyEval_AcquireThread() теперь завершают текущий поток, если вызываются во время завершения интерпретатора, что делает их согласованными с PyEval_RestoreThread(), Py_END_ALLOW_THREADS() и PyGILState_Ensure(). Если такое поведение нежелательно, защитите вызов, проверив _Py_IsFinalizing() или sys.is_finalizing(). (Предоставлено Джоанной Нанджекье в bpo-36475.)

Изменения в Python API

  • Функция os.getcwdb() теперь использует кодировку UTF-8 в Windows, а не кодовую страницу ANSI: объяснение см. в PEP 529. Функция больше не является устаревшей в Windows. (Предоставлено Виктором Стиннером в bpo-37412)

  • subprocess.Popen теперь может использовать os.posix_spawn() в некоторых случаях для повышения производительности. В подсистеме Windows для Linux и пользовательской эмуляции QEMU конструктор Popen, использующий os.posix_spawn(), больше не вызывает исключения при таких ошибках, как «отсутствует программа». Вместо этого дочерний процесс завершается ошибкой с ненулевым returncode. (Предоставлено Джоанной Нанджекье и Виктором Стиннером в bpo-35537.)

  • Аргумент preexec_fn * subprocess.Popen больше не совместим с субинтерпретаторами. Использование параметра в субинтерпретаторе теперь вызывает RuntimeError. (Предоставлено Эриком Сноу в bpo-34651, изменено Кристианом Хеймсом в bpo-37951.)

  • Метод imap.IMAP4.logout() больше не игнорирует произвольные исключения. (Предоставлено Виктором Стиннером в bpo-36348.)

  • Функция platform.popen() была удалена после того, как она устарела с Python 3.3: вместо нее использовать os.popen(). (Предоставлено Виктором Стиннером в bpo-35345)

  • Функция statistics.mode() больше не вызывает исключение при передаче мультимодальных данных. Вместо этого он возвращает первый режим, обнаруженный во входных данных. (Предоставлено Раймондом Хеттингером в bpo-35892)

  • Метод selection() класса tkinter.ttk.Treeview больше не принимает аргументы. Использование его с аргументами для изменения выбора было устаревшим в Python 3.6. Использовать специальные методы, такие как selection_set(), для изменения выделения. (Предоставлено Сергеем Сторчакой, bpo-31508.)

  • Методы writexml(), toxml() и toprettyxml() для xml.dom.minidom и метод write() для xml.etree теперь сохраняют порядок атрибутов, указанный пользователем. (Предоставлено Диего Рохасом и Раймондом Хеттингером в bpo-34160)

  • База данных dbm.dumb, открытая с флагами 'r', теперь доступна только для чтения. dbm.dumb.open() с флагами 'r' и 'w' больше не создает базу данных, если она не существует. (Предоставлено Сергеем Сторчакой, bpo-32749.)

  • Метод doctype(), определенный в подклассе XMLParser, больше не будет вызываться и будет выдавать RuntimeWarning вместо DeprecationWarning. Определите метод doctype() на целевом объекте для обработки объявления типа XML. (Предоставлено Сергеем Сторчакой в bpo-29209.)

  • Теперь вызывается RuntimeError, когда пользовательский метакласс не предоставляет запись __classcell__ в пространстве имен, переданном в type.__new__. DeprecationWarning был выпущен в Python 3.6–3.7. (Предоставлено Сергеем Сторчакой, bpo-23722.)

  • Класс cProfile.Profile теперь можно использовать в качестве менеджера контекста. (Предоставлено Скоттом Сандерсоном в bpo-29235.)

  • shutil.copyfile(), shutil.copy(), shutil.copy2(), shutil.copytree() и shutil.move() используют системные вызовы быстрого копирования для разных платформ (см. раздел Операции эффективного копирования, зависящие от платформы).

  • Размер буфера по умолчанию shutil.copyfile() в Windows изменён с 16 КиБ на 1 МиБ.

  • Структура PyGC_Head полностью изменилась. Весь код, касающийся члена структуры, должен быть переписан. (См. bpo-33597.)

  • Структура PyInterpreterState перемещена во «внутренние» файлы заголовков (в частности, Include/internal/pycore_pystate.h). Непрозрачный PyInterpreterState по-прежнему доступен как часть общедоступного API (и стабильного ABI). В документации указано, что ни одно из полей структуры не является общедоступным, поэтому мы надеемся, что никто их не использовал. Однако, если вы полагаетесь на одно или несколько из этих частных полей и у вас нет альтернативы, пожалуйста, открыть проблему BPO. Мы будем работать над тем, чтобы помочь вам в настройке (возможно, включая добавление функций доступа к общедоступному API). (См. bpo-35886.)

  • Метод mmap.flush() теперь возвращает None в случае успеха и вызывает исключение в случае ошибки на всех платформах. Раньше его поведение зависело от платформы: в случае успеха возвращалось ненулевое значение; ноль был возвращен при ошибке под Windows. В случае успеха было возвращено нулевое значение; при ошибке в Unix возникло исключение. (Предоставлено Беркером Пексагом в bpo-2122.)

  • Модули xml.dom.minidom и xml.sax больше не обрабатывают внешние объекты по умолчанию. (Предоставлено Кристианом Хеймсом в bpo-17239.)

  • Удаление ключа из базы данных dbm, доступной только для чтения (dbm.dumb, dbm.gnu или dbm.ndbm), вызывает error (dbm.dumb.error, dbm.gnu.error или dbm.ndbm.error) вместо KeyError. (Предоставлено Сян Чжаном в bpo-33106)

  • Упрощенный AST для литералов. Все константы будут представлены как экземпляры ast.Constant. Создание экземпляров старых классов Num, Str, Bytes, NameConstant и Ellipsis вернет экземпляр Constant. (Предоставлено Сергеем Сторчакой, bpo-32892.)

  • expanduser() в Windows теперь предпочитает переменную среды USERPROFILE и не использует HOME, который обычно не устанавливается для обычных учётных записей пользователей. (Предоставлено Энтони Соттилем в bpo-36264)

  • Исключение asyncio.CancelledError теперь наследуется от BaseException, а не Exception, и больше не наследуется от concurrent.futures.CancelledError. (Предоставлено Юрием Селивановым в bpo-32528.)

    Функция asyncio.wait_for() теперь правильно ожидает отмены при использовании экземпляра asyncio.Task. Раньше при достижении timeout отменяли и сразу возвращали. (Предоставлено Элвисом Пранскевичусом в bpo-32751.)

  • Функция asyncio.BaseTransport.get_extra_info() теперь возвращает безопасный для использования объект сокета, когда «сокет» передается в параметр name. (Предоставлено Юрием Селивановым в bpo-37027.)

  • asyncio.BufferedProtocol перешёл на стабильный API.

  • Зависимости DLL для модулей расширения и DLL, загружаемых с ctypes в Windows, теперь разрешаются более безопасно. Только системные пути, каталог, содержащий файл DLL или PYD, и каталоги, добавленные с помощью add_dll_directory(), ищутся на предмет зависимостей во время загрузки. В частности, PATH и текущий рабочий каталог больше не используются, и их модификации больше не будут влиять на нормальное разрешение DLL. Если ваше приложение использует эти механизмы, вам следует проверить наличие add_dll_directory() и, если он существует, использовать его для добавления каталога DLL при загрузке библиотеки. Обратите внимание, что пользователям Windows 7 необходимо убедиться, что установлен Центр обновления Windows KB2533623 (это также проверяется установщиком). (Предоставлено Стивом Дауэром в bpo-36085.)
  • Заголовочные файлы и функции, связанные с pgen, были удалены после их замены чистой реализацией Python. (Предоставлено Пабло Галиндо в bpo-36623.)
  • types.CodeType имеет новый параметр во второй позиции конструктора (posonlyargcount) для поддержки позиционных аргументов, определенных в PEP 570. Первый аргумент (argcount) теперь представляет общее количество позиционных аргументов (включая только позиционные аргументы). Новый метод replace() из types.CodeType может использоваться для обеспечения соответствия кода требованиям завтрашнего дня.

Изменения в C API

В структуре PyCompilerFlags появилось новое поле cf_feature_version. Его следует инициализировать как PY_MINOR_VERSION. Поле игнорируется по умолчанию и используется тогда и только тогда, когда в cf_flags установлен флаг PyCF_ONLY_AST. (Предоставлено Гвидо ван Россумом в bpo-35766.)
  • Функция PyEval_ReInitThreads() удалена из C API. Его не следует вызывать явно: использовать вместо него PyOS_AfterFork_Child(). (Предоставлено Виктором Стиннером в bpo-36728)

  • В Unix расширения C больше не связаны с libpython, за исключением Android и Cygwin. Когда Python встроен, libpython должен загружаться не с RTLD_LOCAL, а с RTLD_GLOBAL. Ранее при использовании RTLD_LOCAL уже было невозможно загрузить расширения C, которые не были связаны с libpython, например расширения C стандартной библиотеки, созданной разделом *shared* Modules/Setup. (Предоставлено Виктором Стиннером в bpo-21536.)

  • Использование вариантов форматов # при синтаксическом анализе или построении значения (например, PyArg_ParseTuple(), Py_BuildValue(), PyObject_CallFunction() и т. д.) Без определения PY_SSIZE_T_CLEAN вызывает DeprecationWarning. Он будет удален в 3.10 или 4.0. Подробности читайте в Анализ аргументов и сборка значений. (Предоставлено Инадой Наоки в bpo-36381.)

  • Экземпляры типов с распределением в куче (например, созданные с помощью PyType_FromSpec()) содержат ссылку на свой объект типа. Увеличение числа ссылок для объектов этого типа было перемещено из PyType_GenericAlloc() в функции более низкого уровня, PyObject_Init() и PyObject_INIT(). Это заставляет типы, созданные с помощью PyType_FromSpec(), вести себя как другие классы в управляемом коде.

    Статически выделенные типы не затрагиваются.

    В подавляющем большинстве случаев побочных эффектов быть не должно. Однако типы, которые вручную увеличивают счётчик ссылок после выделения экземпляра (возможно, чтобы обойти ошибку), теперь могут стать бессмертными. Чтобы этого избежать, этим классам необходимо вызывать Py_DECREF для объекта типа во время освобождения экземпляра.

    Чтобы правильно перенести эти типы в 3.8, внесите следующие изменения:

    • Удалить Py_INCREF на объекте типа после выделения экземпляра — если таковой имеется. Это может произойти после вызова PyObject_New(), PyObject_NewVar(), PyObject_GC_New(), PyObject_GC_NewVar() или любого другого настраиваемого распределителя, использующего PyObject_Init() или PyObject_INIT().

      Пример:

      static foo_struct *
      foo_new(PyObject *type) {
          foo_struct *foo = PyObject_GC_New(foo_struct, (PyTypeObject *) type);
          if (foo == NULL)
              return NULL;
      #if PY_VERSION_HEX < 0x03080000
          // Обходной путь для проблемы Python 35810; больше не требуется в Python 3.8
          PY_INCREF(type)
      #endif
          return foo;
      }
      
    • Убедитесь, что все пользовательские функции tp_dealloc для типов, выделенных в куче, уменьшают счётчик ссылок типа.

      Пример:

      static void
      foo_dealloc(foo_struct *instance) {
          PyObject *type = Py_TYPE(instance);
          PyObject_GC_Del(instance);
      #if PY_VERSION_HEX >= 0x03080000
          // Это не было необходимо до Python 3.8 (проблема Python 35810)
          Py_DECREF(type);
      #endif
      }
      

    (Предоставлено Эдди Элизондо в bpo-35810.)

  • Макрос: c:macro:Py_DEPRECATED() был реализован для MSVC. Теперь макрос должен быть помещён перед именем Символа.

    Пример:

    Py_DEPRECATED(3.8) PyAPI_FUNC(int) Py_OldFunction(void);
    

    (Предоставлено Закери Спитцем в bpo-33407.)

  • Интерпретатор больше не претендует на поддержку двоичной совместимости типов расширений между релизами функций. PyTypeObject, экспортированный сторонним модулем расширения, должен иметь все слоты, ожидаемые в текущей версии Python, включая tp_finalize (Py_TPFLAGS_HAVE_FINALIZE больше не проверяется перед чтением tp_finalize).

    (Предоставлено Антуаном Питру в bpo-32388.)

  • Функции PyNode_AddChild() и PyParser_AddToken() теперь принимают два дополнительных аргумента int end_lineno и end_col_offset.

  • Файл libpython38.a, позволяющий инструментам MinGW напрямую связываться с python38.dll, больше не включен в обычный дистрибутив Windows. Если вам нужен этот файл, его можно сгенерировать с помощью инструментов gendef и dlltool, которые являются частью пакета MinGW binutils:

    gendef - python38.dll > tmp.def
    dlltool --dllname python38.dll --def tmp.def --output-lib libpython38.a
    

    Местоположение установленного pythonXY.dll будет зависеть от параметров установки, а также от версии и языка Windows. См. Использование Python в Windows для получения дополнительной информации. Полученная библиотека должна быть помещена в тот же каталог, что и pythonXY.lib, который обычно является каталогом libs в вашей установке Python.

    (Предоставлено Стивом Дауэром в bpo-37351.)

Изменения байт-кода CPython

  • Цикл интерпретатора был упрощён за счёт переноса логики разворачивания стека блоков в компилятор. Теперь компилятор выдает явные инструкции для настройки стека значений и вызова кода очистки для break, continue и return.

    Удалены коды операций BREAK_LOOP, CONTINUE_LOOP, SETUP_LOOP и SETUP_EXCEPT. Добавлены новые коды операций ROT_FOUR, BEGIN_FINALLY, CALL_FINALLY и POP_FINALLY. Изменено поведение END_FINALLY и WITH_CLEANUP_START.

    (Предоставлено Марком Шенноном, Антуаном Питру и Сергеем Сторчакой в bpo-17611)

  • Добавлен новый код операции END_ASYNC_FOR для обработки исключений, возникающих при ожидании следующего элемента в цикле async for. (Предоставлено Сергеем Сторчакой, bpo-33041.)

  • Теперь MAP_ADD ожидает значение в качестве первого элемента в стеке, а ключ — в качестве второго элемента. Это изменение было внесено, поэтому ключ всегда вычисляется перед значением в интерпретациях словаря, как это предлагается PEP 572. (Предоставлено Йорном Хейсслером в bpo-35224.)

Демонстрации и инструменты

Добавлен тестовый сценарий для определения времени различных способов доступа к переменным: Tools/scripts/var_access_benchmark.py. (Предоставлено Реймондом Хиттингером в bpo-35884)

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

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

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

Variable and attribute write access:
    write_local                      4.6     8.7     9.3     5.5     5.3     4.3
    write_nonlocal                   7.3    10.5    11.1     5.6     5.5     4.7
    write_global                    15.9    19.7    21.2    18.0    18.0    15.8
    write_classvar                  81.9    92.9    96.0   104.6   102.1    39.2
    write_instancevar               36.4    44.6    45.8    40.0    38.9    35.5
    write_instancevar_slots         28.7    35.6    36.1    27.3    26.6    25.7

Data structure read access:
    read_list                       19.2    24.2    24.5    20.8    20.8    19.0
    read_deque                      19.9    24.7    25.5    20.2    20.6    19.8
    read_dict                       19.7    24.3    25.7    22.3    23.0    21.0
    read_strdict                    17.9    22.6    24.3    19.5    21.2    18.9

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

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

Timing loop:
    loop_overhead                    0.3     0.5     0.6     0.4     0.3     0.3

Тесты были измерены на Intel® Core™ i7-4960HQ процессоре с 64-разрядными сборками macOS, найденными по адресу python.org. Сценарий тестирования отображает время в наносекундах.

Заметные изменения в Python 3.8.1

Из-за серьезных проблем с безопасностью параметр reuse_address для asyncio.loop.create_datagram_endpoint() больше не поддерживается. Это связано с поведением параметра сокета SO_REUSEADDR в UDP. Для получения дополнительных сведений см. документацию для loop.create_datagram_endpoint(). (Предоставлено Кайлом Стэнли, Антуаном Питру и Юрием Селивановым в bpo-37228.)

Заметные изменения в Python 3.8.2

Исправлена регрессия с обратным вызовом ignore для shutil.copytree(). Типы аргументов теперь снова str и List[str]. (Предоставлено Мануэлем Баркхау и Джампаоло Родола в bpo-39390.)

Заметные изменения в Python 3.8.3

Постоянные значения будущих флагов в модуле __future__ обновляются, чтобы предотвратить конфликт с флагами компилятора. Ранее PyCF_ALLOW_TOP_LEVEL_AWAIT конфликтовал с CO_FUTURE_DIVISION. (Предоставлено Батуханом Таская в bpo-39562)

Заметные изменения в Python 3.8.8

Более ранние версии Python позволяли использовать как ;, так и & в качестве разделителей параметров запроса в urllib.parse.parse_qs() и urllib.parse.parse_qsl(). Из соображений безопасности и в соответствии с новыми рекомендациями W3C это было изменено, чтобы разрешить использование только одного ключа-разделителя & по умолчанию. Это изменение также влияет на cgi.parse() и cgi.parse_multipart(), поскольку они используют затронутые функции внутри. Для получения дополнительных сведений см. соответствующую документацию. (Предоставлено Адамом Гольдшмидтом, Сентил Кумаран и Кен Джин в bpo-42967.)