Що нового в Python 3.8

Редактор

Raymond Hettinger

This article explains the new features in Python 3.8, compared to 3.7. For full details, see the changelog.

Підсумок – основні моменти випуску

Нові можливості

Вирази присвоєння

Існує новий синтаксис :=, який призначає значення змінним як частину більшого виразу. Його ласкаво називають «оператором моржа» через його схожість з очима та бивнями моржа <https://en.wikipedia.org/wiki/Walrus#/media/File:Pacific_Walrus_-_Bull_(8247646168).jpg>.

У цьому прикладі вираз присвоєння допомагає уникнути виклику 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, які обчислюють значення для перевірки завершення циклу, а потім знову потребують того самого значення в тілі циклу:

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

Лише позиційні параметри

There is a new function parameter syntax / to indicate that some function parameters must be specified positionally and cannot be used as keyword arguments. This is the same notation shown by help() for C functions annotated with Larry Hastings“ Argument Clinic tool.

У наступному прикладі параметри 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

Додаткова перевага позначення параметра як лише позиційного полягає в тому, що це дозволяє змінювати ім’я параметра в майбутньому без ризику зламати код клієнта. Наприклад, у модулі statistic назва параметра 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 для повного опису.

(Надав Pablo Galindo в bpo-36540.)

Паралельний кеш файлової системи для скомпільованих файлів байт-коду

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

Розташування кешу повідомляється в sys.pycache_prefix (None вказує на розташування за умовчанням у підкаталогах __pycache__).

(Надано Карлом Майєром у bpo-33499.)

Збірка налагодження використовує той самий ABI, що й збірка випуску

Тепер Python використовує той самий ABI, незалежно від того, чи створено його в режимі випуску чи налагодження. У Unix, коли Python створено в режимі налагодження, тепер можна завантажувати розширення C, створені в режимі випуску, і розширення C, створені за допомогою стабільного ABI.

Release builds and debug builds are now ABI compatible: defining the Py_DEBUG macro no longer implies the Py_TRACE_REFS macro, which introduces the only ABI incompatibility. The Py_TRACE_REFS macro, which adds the sys.getobjects() function and the PYTHONDUMPREFS environment variable, can be set using the new ./configure --with-trace-refs build option. (Contributed by Victor Stinner in 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-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 дозволяють краще контролювати відображення результату виразу:

>>> 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 додає Audit Hook і 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.)

PEP 590: Vectorcall: швидкий протокол виклику для CPython

Протокол Vectorcall is added to the Python/C API. It is meant to formalize existing optimizations which were already done for various classes. Any static type implementing a callable can use this protocol.

Наразі це тимчасово. Мета полягає в тому, щоб зробити його повністю публічним у 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 дає змогу написати чисельник, знаменник = 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 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, і відповідний ступінь цієї оберненої величини для інших від’ємних показників степеня. Наприклад, щоб обчислити модульний мультиплікативний обернений 38 за модулем 137, напишіть:

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

    Модульні обернені виникають при розв’язуванні «лінійних діофантових рівнянь <https://en.wikipedia.org/wiki/Diophantine_equation>» _. Наприклад, щоб знайти цілочисельні розв’язки для 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, так що спочатку обчислюється ключ, а потім значення:

    >>> # 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 тепер мають атрибути 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() має бути кращим способом запуску асинхронних програм.

(Надав Юрій Селіванов у 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.)

Асинхронним завданням тепер можна присвоювати назви, передавши аргумент ключового слова 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.)

вбудовані елементи

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

колекції

Метод _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:
      # 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.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(), який перетворює методи на загальні функції за допомогою 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() для відтворюваного виведення. (Надав Guo Ci Teo в bpo-34898.)

Виняток BadGzipFile тепер викликається замість OSError для певних типів недійсних або пошкоджених файлів gzip. (Надано Філіпом Грущинським, Мікеле Орру та Закері Шпітцем у bpo-6584.)

IDLE і idlelib

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

Додайте «Run Customized» до меню «Run», щоб запустити модуль із налаштованими налаштуваннями. Будь-які введені аргументи командного рядка додаються до 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.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

In development mode (-X env) and in debug build, the io.IOBase finalizer now logs the exception if the close() method fails. The exception is ignored silently by default in release build. (Contributed by Victor Stinner in 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. (Надано Weipeng Hong у bpo-31553.)

лісозаготівля

Додано аргумент ключового слова force до logging.basicConfig() Якщо встановлено значення true, усі існуючі обробники, приєднані до кореневого реєстратора, видаляються та закриваються перед виконанням конфігурації, визначеної іншими аргументами.

Це вирішує давню проблему. Після виклику реєстратора або basicConfig() наступні виклики basicConfig() мовчки ігнорувалися. Через це було складно оновлювати, експериментувати з різними параметрами конфігурації журналу або навчати їх за допомогою інтерактивної підказки або блокнота Jupyter.

(Запропоновано Raymond Hettinger, реалізовано Dong-hee 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

(Надано Yash Aggarwal, Keller Fuchs, Serhiy Storchaka та Raymond Hettinger у 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.)

ос

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

Було додано нову функцію os.memfd_create() для обгортання системного виклику memfd_create(). (Надано Zackery Spytz і Christian Heimes у 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(), який створює жорстке посилання, що вказує на шлях. (Надано Joannah Nanjekye у bpo-26978)

маринований огірок

Розширення pickle, що створюють субкласи оптимізованого для C Pickler, тепер можуть перевизначати логіку маринування функцій і класів, визначаючи спеціальний метод 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'}

(Надав Ремі Лапейр у bpo-30670.)

py_compile

py_compile.compile() тепер підтримує тихий режим. (Надано Joannah Nanjekye у bpo-22640.)

шлекс

Нова функція shlex.join() діє як зворотна функція shlex.split(). (Надав Бо Бейлс у bpo-32102.)

шутил

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

shutil.make_archive() тепер за замовчуванням використовує сучасний формат pax (POSIX.1-2001) для нових архівів для покращення переносимості та відповідності стандартам, успадкованому від відповідних змін у модулі tarfile. (Надано C.A.M. Gerlach у 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.unraisablehook(), яку можна перевизначати, щоб керувати обробкою «виключних ситуацій, які не можна викликати». Він викликається, коли сталася виняткова ситуація, але Python не може її впоратися. Наприклад, коли деструктор викликає виняток або під час збирання сміття (gc.collect()). (Надав Віктор Стіннер у bpo-36829.)

tarfile

Модуль tarfile тепер за замовчуванням використовує сучасний формат pax (POSIX.1-2001) для нових архівів замість попереднього, специфічного для GNU. Це покращує міжплатформенну переносимість завдяки узгодженому кодуванню (UTF-8) у стандартизованому та розширюваному форматі та пропонує кілька інших переваг. (Надано C.A.M. Gerlach у bpo-36268.)

різьблення

Додайте нову функцію threading.excepthook(), яка обробляє неперехоплені винятки threading.Thread.run(). Його можна змінити, щоб керувати обробкою неперехоплених винятків threading.Thread.run(). (Надав Віктор Стіннер у bpo-1230540.)

Додайте нову функцію threading.get_native_id() і атрибут native_id до класу threading.Thread. Вони повертають власний інтегральний ідентифікатор потоку поточного потоку, призначений ядром. Ця функція доступна лише на певних платформах, див. get_native_id для отримання додаткової інформації. (Надав Джейк Теслер у bpo-36084.)

токенізувати

Модуль tokenize тепер неявно випромінює маркер NEWLINE, якщо надається вхідні дані, які не мають кінцевого нового рядка. Ця поведінка тепер відповідає внутрішнім функціям C tokenizer. (Надав Аммар Аскар у bpo-33899.)

tkinter

Додано методи selection_from(), selection_present(), selection_range() та selection_to() у клас tkinter.Spinbox. (Надано Juliette Monsel у 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(). Остаточний кваліфікатор наказує статичному засобу перевірки типів обмежити створення підкласів, перевизначення чи перепризначення:

    pi: Final[float] = 3.1415926536
    
  • Визначення протоколу. Перегляньте PEP 544, typing.Protocol і typing.runtime_checkable(). Прості азбуки, такі як typing.SupportsInt тепер є підкласами Protocol.

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

  • Нові функції typing.get_origin() і typing.get_args().

unicodedata

The unicodedata module has been upgraded to use the Unicode 12.1.0 release.

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

unittest

Додано AsyncMock для підтримки асинхронної версії Mock. Також додано відповідні нові функції assert для тестування. (Надано Лізою Роуч у bpo-26467).

Додано addModuleCleanup() і addClassCleanup() до unittest для підтримки очищення для setUpModule() і setUpClass(). (Надано Лізою Роуч у bpo-24412.)

Кілька імітаційних функцій підтвердження тепер також друкують список фактичних викликів у разі невдачі. (Надано Петтером Страндмарком у 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.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 не встановлені;

    • виконуваний шлях містить каталог.

    (Надано Джоанною Нанджекі та Віктором Стіннером у bpo-35537.)

  • shutil.copyfile(), shutil.copy(), shutil.copy2(), shutil.copytree() і shutil.move() використовують спеціальну для платформи «швидку -copy» системні виклики в Linux і macOS для більш ефективного копіювання файлу. «швидке копіювання» означає, що операція копіювання відбувається всередині ядра, уникаючи використання буферів простору користувача в Python, як у «outfd.write(infd.read())». У Windows shutil.copyfile() використовує більший розмір буфера за замовчуванням (1 МіБ замість 16 КіБ) і використовується варіант memoryview() на основі shutil.copyfileobj(). Прискорення копіювання файлу розміром 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__, щоб зменшити обсяг пам’яті. (Надано Wouter Bolsterlee і Tal Einat у bpo-30977)

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

  • Прискорений пошук полів у collections.namedtuple(). Тепер вони більш ніж у два рази швидші, що робить їх найшвидшою формою пошуку змінних екземплярів у Python. (Надано Реймондом Геттінгером, Пабло Галіндо та Джо Джевником, Сергієм Сторчакою в bpo-32492.)

  • Конструктор list не розподіляє внутрішній буфер елементів, якщо ітерація введення має відому довжину (введення реалізує __len__). Це робить створений список у середньому на 12% меншим. (Надано Реймондом Геттінгером і Пабло Галіндо в bpo-33234.)

  • Подвоєна швидкість запису змінних класу. Коли атрибут не-dunder оновлювався, виникав непотрібний виклик для оновлення слотів. (Надано Стефаном Бенелем, Пабло Галіндо Сальгадо, Раймондом Геттінгером, Нілом Шеменауером і Сергієм Сторчакою в 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.)

Застаріле

Видалення API та функцій

З Python 3.8 видалено наступні функції та API:

  • Починаючи з Python 3.3, імпорт азбуки з 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(). (Надано Joannah Nanjekye у bpo-36475.)

Зміни в API Python

  • Функція 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-декларації doctype. (Надав Сергій Сторчака в 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() використовують спеціальну для платформи «швидку -copy» системні виклики (див. розділ Залежні від платформи ефективні операції копіювання).

  • shutil.copyfile() розмір буфера за замовчуванням у Windows змінено з 16 KiB на 1 MiB.

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

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

  • Метод mmap.flush() тепер повертає None у разі успіху та викликає виняток у разі помилки на всіх платформах. Раніше його поведінка залежала від платформи: ненульове значення поверталося в разі успіху; нуль було повернуто через помилку під Windows. У разі успіху було повернуто нульове значення; виняток було викликано помилкою під Unix. (Надано Berker Peksag у 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. (Надав Xiang Zhang у 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. Раніше, після досягнення тайм-ауту, він скасовувався та негайно повертався. (Надав Елвіс Пранскявічус у bpo-32751.)

  • Функція asyncio.BaseTransport.get_extra_info() тепер повертає безпечний для використання об’єкт socket, коли „socket“ передається в параметр name. (Надав Юрій Селіванов у 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 за замовчуванням.

Зміни в C API

  • The PyCompilerFlags structure got a new cf_feature_version field. It should be initialized to PY_MINOR_VERSION. The field is ignored by default, and is used if and only if PyCF_ONLY_AST flag is set in cf_flags. (Contributed by Guido van Rossum in 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(), поводитися як інші класи в керованому коді.

    Statically allocated types are not affected.

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

  • Для MSVC реалізовано макрос Py_DEPRECATED(). Тепер макрос потрібно розмістити перед назвою символу.

    приклад:

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

Попередні версії Python дозволяли використовувати як ;, так і & як роздільники параметрів запиту в urllib.parse.parse_qs() і urllib.parse.parse_qsl(). З міркувань безпеки та для відповідності новим рекомендаціям W3C це було змінено, щоб дозволити лише один роздільний ключ із & за замовчуванням. Ця зміна також впливає на cgi.parse() і cgi.parse_multipart(), оскільки вони використовують уражені функції внутрішньо. Щоб дізнатися більше, перегляньте відповідну документацію. (Надано Адамом Ґолдшмідтом, Сентилом Кумараном і Кеном Джином у bpo-42967.)

Помітні зміни в Python 3.8.12

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

(Спочатку надано Крістіаном Хеймсом у bpo-36384, а також перенесено до 3.8 Ахрафом Мерзукі.)