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

Редактор:

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

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

Резюме - Основные моменты выпуска

Новые возможности

Выражения заданий

Появился новый синтаксис :=, который присваивает значения переменным как части большего выражения. Его ласково называют «оператором моржа» из-за сходства с the eyes and tusks of a walrus.

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

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

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

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

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

# Loop over fixed length blocks
while (block := f.read(256)) != '':
    process(block)

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

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

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

Полное описание см. в разделе PEP 572.

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

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

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

В следующем примере параметры 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 cannot be a keyword argument
f(10, 20, 30, 40, 50, f=60)           # e must be a keyword argument

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

def divmod(a, b, /):
    "Emulate the built in divmod() function"
    return (a // b, a % b)

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

len(obj='hello')  # The "obj" keyword argument impairs readability

Еще одним преимуществом маркировки параметра как позиционного является то, что она позволяет изменять имя параметра в будущем без риска сломать клиентский код. Например, в модуле 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 and b are used in two ways
10 20 {'a': 1, 'b': 2, 'c': 3}

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

class Counter(dict):

    def __init__(self, iterable=None, /, **kwds):
        # Note "iterable" is a possible keyword argument

Полное описание см. в разделе PEP 570.

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

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

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

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

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

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

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

Релизные сборки и debug builds теперь совместимы по 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 в приложение, в команду python3-config --libs --embed нужно передать новый параметр --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-strings. Строка 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-string format specifiers позволяют лучше контролировать отображение результата выражения:

>>> 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 добавляет крючок аудита и верифицированный открытый крючок. Оба доступны как из Python, так и из нативного кода, что позволяет приложениям и фреймворкам, написанным на чистом Python, использовать преимущества дополнительных уведомлений, а также позволяет встраивателям или системным администраторам развертывать сборки Python, в которых аудит всегда включен.

Подробную информацию см. в разделе PEP 578.

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

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

Новые структуры:

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

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

Документацию см. в разделе Python Initialization Configuration.

Полное описание см. в разделе PEP 587.

(Внесено Виктором Стиннером в bpo-36763).

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

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

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

Полное описание см. в разделе PEP 590.

(При участии Йеруна Демейера, Марка Шеннона и Петра Викторина в bpo-36974).

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

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

Протокол pickle 5 вводит поддержку внеполосных буферов, в которых 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} в regular expressions:

    >>> 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(). (Внесено Rémi Lapeyre в 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 maggie')
    ('SIMPSONS', 'homer', 'marge', 'bart', 'lisa', 'maggie')
    

    (Предоставлено Дэвидом Катбертом и Джорданом Чепменом в 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, и подходящая мощность этой обратной величины для других отрицательных экспонент. Например, чтобы вычислить modular multiplicative inverse от 38 по модулю 137, напишите:

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

    Модульные инверсии возникают при решении linear Diophantine equations. Например, чтобы найти целочисленные решения для 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 comprehensions были синхронизированы с dict literals так, что ключ вычисляется первым, а значение - вторым:

    >>> # Dict comprehension
    >>> cast = {input('role? '): input('actor? ') for i in range(2)}
    role? King Arthur
    actor? Chapman
    role? Black Knight
    actor? Cleese
    
    >>> # Dict literal
    >>> 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 обеспечивает (предварительную) поддержку чтения метаданных из пакетов сторонних разработчиков. Например, он может извлечь номер версии установленного пакета, список точек входа и многое другое:

    >>> # Note following example requires that the popular "requests"
    >>> # package has been installed.
    >>>
    >>> 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. Эта функция может быть использована для выполнения coroutine и возврата результата при автоматическом управлении циклом событий. Например:

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 в bpo-33530).

buildins

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

коллекции

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

cProfile

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

import cProfile

with cProfile.Profile() as profiler:
      # code to be profiled
      ...

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

csv

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

проклятия

Добавлена новая переменная, содержащая структурированную информацию о версии базовой библиотеки 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(), преобразующий методы в generic functions с помощью single dispatch:

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).

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

IDLE и idlelib

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

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

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

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

Новое в версии 3.8.1:

Добавьте возможность отключения мигания курсора. (Внесено Zackery Spytz в bpo-4603).

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

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

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

осмотреть

Функция 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) и в debug build финализатор 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).

ведение журнала

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

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

(Предложено Raymond Hettinger, реализовано Donghee Na и рассмотрено Vinay Sajip в bpo-33897).

математика

Добавлена новая функция 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)    # Permutations of 10 things taken 3 at a time
720
>>> math.comb(10, 3)    # Combinations of 10 things taken 3 at a time
120

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

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

>>> r = 650320427
>>> s = r ** 2
>>> isqrt(s - 1)         # correct
650320426
>>> floor(sqrt(s - 1))   # incorrect
650320427

(Внесено Марком Дикинсоном в bpo-36887).

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

mmap

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

многопроцессорная обработка

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

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

os

В Windows добавлена новая функция add_dll_directory() для указания дополнительных путей поиска нативных зависимостей при импорте модулей расширения или загрузке 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) Обратите внимание, что link_to был устаревшим в 3.10 и удален в 3.12 в пользу метода hardlink_to, добавленного в 3.10, который соответствует семантике существующего метода symlink_to.

маринованный огурец

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

plistlib

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

pprint

Модуль pprint добавил параметр sort_dicts к нескольким функциям. По умолчанию эти функции продолжают сортировать словари перед рендерингом или печатью. Однако если sort_dicts имеет значение false, словари сохраняют порядок вставки ключей. Это может быть полезно для сравнения с входными данными 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)                  # Original order
{'source': 'input.txt',
 'operation': 'filter',
 'destination': 'output.txt'}
>>> pprint(d, width=40)              # Keys sorted alphabetically
{'destination': 'output.txt',
 'operation': 'filter',
 'source': 'input.txt'}

(Предоставлено Rémi Lapeyre в bpo-30670).

py_compile

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

shlex

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

ШУТИЛ

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

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

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

сокет

Добавлены удобные функции 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.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)            # Chance of being under 3 degrees
0.3184678262814532
>>> # Relative chance of being 7 degrees versus 10 degrees
>>> temperature_feb.pdf(7) / temperature_feb.pdf(10)
1.2039930378537762

>>> el_niño = NormalDist(4, 2.5)
>>> temperature_feb += el_niño        # Add in a climate effect
>>> temperature_feb
NormalDist(mu=10.0, sigma=6.830080526611674)

>>> temperature_feb * (9/5) + 32      # Convert to Fahrenheit
NormalDist(mu=50.0, sigma=12.294144947901014)
>>> temperature_feb.samples(3)        # Generate random samples
[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.excepthook(), которая обрабатывает не пойманные threading.Thread.run() исключения. Ее можно переопределить, чтобы управлять обработкой не пойманных threading.Thread.run() исключений. (Внесено Виктором Стиннером в bpo-1230540).

Добавьте новую функцию threading.get_native_id() и атрибут native_id в класс threading.Thread. Они возвращают собственный интегральный Thread ID текущего потока, назначенный ядром. Эта функция доступна только на некоторых платформах, более подробную информацию см. в разделе 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).

время

Добавлены новые часы CLOCK_UPTIME_RAW для macOS 10.12. (Внесено Joannah Nanjekye в bpo-35702).

набор текста

Модуль 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(). Квалификатор 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 был обновлен для использования релиза Unicode 12.1.0.

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

unittest

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

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

Некоторые функции mock 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 равно false;

    • Параметры preexec_fn, pass_fds, cwd и start_new_session не установлены;

    • путь исполняемого содержит каталог.

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

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

  • shutil.copytree() использует функцию os.scandir(), а все функции копирования, зависящие от нее, используют кэшированные значения os.stat(). Ускорение при копировании каталога с 8000 файлами составляет около +9 % в Linux, +20 % в Windows и +30 % на SMB-хосте Windows. Кроме того, количество вызовов системы 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 - это частный внутренний API на языке C, специфичный для 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).

Утратившие актуальность

  • Команда distutils bdist_wininst теперь устарела, вместо нее используйте bdist_wheel (wheel packages). (Внесено Виктором Стиннером в bpo-37481).

  • Устаревшие методы getchildren() и getiterator() в модуле ElementTree теперь выдают DeprecationWarning вместо PendingDeprecationWarning. Они будут удалены в Python 3.9. (Внесено Сергеем Сторчакой в bpo-29209).

  • Передача объекта, не являющегося экземпляром concurrent.futures.ThreadPoolExecutor, в loop.set_default_executor() является устаревшей и будет запрещена в Python 3.9. (Внесено Элвисом Пранскевичусом в bpo-34075).

  • Методы __getitem__() в xml.dom.pulldom.DOMEventStream, wsgiref.util.FileWrapper и fileinput.FileInput были устаревшими.

    Реализации этих методов игнорировали параметр index и возвращали вместо него следующий элемент. (Внесено Беркером Пексагом в bpo-9372).

  • Класс typing.NamedTuple отказался от атрибута _field_types в пользу атрибута __annotations__, который содержит ту же информацию. (Внесено Раймондом Хеттингером в bpo-36320).

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

  • Методы ast.NodeVisitor visit_Num(), visit_Str(), visit_Bytes(), visit_NameConstant() и visit_Ellipsis() уже устарели и не будут вызываться в будущих версиях Python. Добавьте метод visit_Constant() для работы со всеми константными узлами. (Внесено Сергеем Сторчакой в bpo-36917).

  • Символ asyncio.coroutine() decorator устарел и будет удален в версии 3.10. Вместо @asyncio.coroutine используйте async def. (Внесено Андреем Светловым в bpo-36921).

  • В asyncio явная передача аргумента loop была устаревшей и будет удалена в версии 3.10 для следующих функций: asyncio.sleep(), asyncio.gather(), asyncio.shield(), asyncio.wait_for(), asyncio.wait(), asyncio.as_completed(), asyncio.Task, asyncio.Lock, asyncio.Event, asyncio.Condition, asyncio.Semaphore, asyncio.BoundedSemaphore, asyncio.Queue, asyncio.create_subprocess_exec() и asyncio.create_subprocess_shell().

  • Явная передача объектов coroutine в asyncio.wait() была устаревшей и будет удалена в версии 3.11. (Внесено Юрием Селивановым в bpo-34790).

  • В модуле gettext устарели следующие функции и методы: lgettext(), ldgettext(), lngettext() и ldngettext(). Они возвращают закодированные байты, и есть вероятность получить неожиданные исключения, связанные с Unicode, если есть проблемы с кодировкой переведенных строк. Гораздо лучше использовать альтернативы, которые возвращают строки в Unicode в Python 3. Эти функции уже давно не работают.

    Функция bind_textdomain_codeset(), методы output_charset() и set_output_charset(), а также параметр codeset функций translation() и install() также устарели, поскольку используются только для функций l*gettext(). (Внесено Сергеем Сторчакой в bpo-33710).

  • Метод isAlive() из threading.Thread был устаревшим. (Внесено Донгхи На в bpo-35283).

  • Многие встроенные функции и функции расширения, принимающие целочисленные аргументы, теперь будут выдавать предупреждение об устаревании для Decimals, Fractions и любых других объектов, которые могут быть преобразованы в целые числа только с потерями (например, у которых есть метод __int__(), но нет метода __index__()). В будущей версии они станут ошибками. (Внесено Сергеем Сторчакой в bpo-36048).

  • Исправлена передача следующих аргументов в качестве аргументов ключевых слов:

    В будущих выпусках Python они будут иметь значение positional-only. (Внесено Сергеем Сторчакой в bpo-36492).

Удаление 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. Все остальные параметры теперь принимают значение keyword-only. (Внесено Сергеем Сторчакой в 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) теперь запрещены в осмыслениях и генераторных выражениях (за исключением выражения iterable в крайнем левом предложении 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).

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

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

  • subprocess.Popen теперь может использовать os.posix_spawn() в некоторых случаях для повышения производительности. В Windows Subsystem for Linux и QEMU User Emulation конструктор 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 doctype. (Внесено Сергеем Сторчакой в bpo-29209).

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

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

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

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

  • Структура PyGC_Head полностью изменилась. Весь код, затрагивающий член struct, должен быть переписан. (См. 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 передано „socket“. (Внесено Юрием Селивановым в bpo-37027).

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

  • Зависимости DLL для модулей расширения и DLL, загружаемых с помощью ctypes в Windows, теперь решаются более надежно. Для поиска зависимостей во время загрузки используются только системные пути, каталог, содержащий DLL или PYD-файл, и каталоги, добавленные с помощью add_dll_directory(). В частности, PATH и текущий рабочий каталог больше не используются, и их изменения больше не влияют на нормальное разрешение DLL. Если ваше приложение полагается на эти механизмы, вам следует проверить наличие add_dll_directory() и, если он существует, использовать его для добавления каталога DLLs при загрузке библиотеки. Обратите внимание, что пользователям Windows 7 необходимо убедиться, что обновление Windows Update KB2533623 установлено (это также проверяется программой установки). (Внесено Стивом Дауэром в bpo-36085).

  • Заголовочные файлы и функции, связанные с pgen, были удалены после его замены на чистую реализацию Python. (Внесено Пабло Галиндо в bpo-36623).

  • types.CodeType имеет новый параметр во второй позиции конструктора (posonlyargcount) для поддержки только позиционных аргументов, определенных в PEP 570. Первый аргумент (argcount) теперь представляет собой общее количество позиционных аргументов (включая только позиционные аргументы). Новый метод replace() из types.CodeType может быть использован, чтобы сделать код устойчивым к будущему.

  • Параметр digestmod для hmac.new() больше не использует дайджест MD5 по умолчанию.

Изменения в API языка C

  • В структуре PyCompilerFlags появилось новое поле cf_feature_version. Оно должно быть инициализировано значением PY_MINOR_VERSION. По умолчанию поле игнорируется, и используется тогда и только тогда, когда в cf_flags установлен флаг PyCF_ONLY_AST. (Внесено Гвидо ван Россумом в bpo-35766).

  • Функция PyEval_ReInitThreads() была удалена из API языка C. Ее не следует вызывать явно: вместо нее используйте 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(), ведут себя в управляемом коде как другие классы.

    Statically allocated types не затрагиваются.

    В подавляющем большинстве случаев побочных эффектов быть не должно. Однако типы, которые вручную увеличивают количество ссылок после выделения экземпляра (возможно, чтобы обойти ошибку), теперь могут стать бессмертными. Чтобы избежать этого, такие классы должны вызывать 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
          // Workaround for Python issue 35810; no longer necessary in 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
          // This was not needed before Python 3.8 (Python issue 35810)
          Py_DECREF(type);
      #endif
      }
      

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

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

    Пример:

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

    (Предоставлено Zackery Spytz в 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 processor под управлением 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]. (Вклад Мануэля Бархау и Джампаоло Родолы в gh-83571).

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

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

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

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

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

Исправление безопасности изменяет поведение ftplib.FTP, чтобы не доверять IPv4-адресу, отправленному с удаленного сервера при установке пассивного канала передачи данных. Вместо этого мы используем IP-адрес ftp-сервера. Для необычного кода, требующего старого поведения, установите для атрибута trust_server_pasv_ipv4_address экземпляра FTP значение True (см. gh-87451).

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

macOS 11.0 (Big Sur) и поддержка Apple Silicon Mac

Начиная с версии 3.8.10, Python теперь поддерживает сборку и запуск на macOS 11 (Big Sur) и на компьютерах Apple Silicon Mac (на базе архитектуры ARM64). Теперь доступен новый универсальный вариант сборки, universal2, позволяющий нативно поддерживать и ARM64, и Intel 64 в одном наборе исполняемых файлов. Обратите внимание, что поддержка «слабых связей» (weaklinking) - сборки двоичных файлов, предназначенных для новых версий macOS, которые будут корректно работать и на старых версиях за счет проверки во время выполнения на отсутствие недостающих функций - не включена в этот бэкпорт с Python 3.9; для поддержки ряда версий macOS продолжайте ориентироваться на самую старую версию в этом ряду и собирать на ней.

(Изначально было внесено Рональдом Оусореном и Лоуренсом Д’Анной в gh-85272, исправлено FX Coudert и Eli Rykoff, и перенесено в 3.8 Максимом Беланжером и Недом Дейли)

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

urllib.parse

Наличие символов новой строки или табуляции в части URL позволяет осуществлять некоторые виды атак. В соответствии со спецификацией WHATWG, которая обновляет RFC 3986, символы ASCII новой строки \n, \r и табуляции \t удаляются из URL парсером в urllib.parse, предотвращая такие атаки. Символы удаления контролируются новой переменной уровня модуля urllib.parse._UNSAFE_URL_BYTES_TO_REMOVE (см. bpo-43882).

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

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

Начиная с Python 3.8.12 модуль ipaddress больше не принимает ведущие нули в строках адресов IPv4. Ведущие нули неоднозначны и интерпретируются некоторыми библиотеками как восьмеричная система счисления. Например, унаследованная функция socket.inet_aton() воспринимает ведущие нули как восьмеричную систему счисления. Реализация glibc современной inet_pton() не принимает ведущие нули.

(Изначально был внесен Кристианом Хаймсом в bpo-36384, а в 3.8 перенесен Ахрафом Мерзуки).

Примечательная функция безопасности в версии 3.8.14

Преобразование между int и str в основаниях, отличных от 2 (двоичное), 4, 8 (восьмеричное), 16 (шестнадцатеричное) или 32, таких как основание 10 (десятичное), теперь вызывает ошибку ValueError, если количество цифр в строковой форме превышает установленный предел, чтобы избежать потенциальных атак типа «отказ в обслуживании» из-за сложности алгоритма. Это смягчение последствий CVE-2020-10735. Это ограничение может быть настроено или отключено с помощью переменной окружения, флага командной строки или sys. API. См. документацию по integer string conversion length limitation. По умолчанию ограничение составляет 4300 цифр в строковой форме.

Заметные изменения в версии 3.8.17

tarfile

  • Методы извлечения в tarfile и shutil.unpack_archive() имеют новый аргумент filter, который позволяет ограничить возможности tar, которые могут быть неожиданными или опасными, например создание файлов вне целевого каталога. Подробности см. в Фильтры для извлечения. В Python 3.12 использование без аргумента filter приводит к появлению DeprecationWarning. В Python 3.14 по умолчанию будет отображаться 'data'. (Внесено Петром Викториным в PEP 706).