
Python 3.15 читає й записує текстові файли в UTF-8 (Unicode Transformation Format, 8 біт), навіть якщо ви не вказали кодування. Раніше на Windows інтерпретатор брав його із системних налаштувань, і для кириличних регіонів це був cp1251. Фінальний реліз заплановано на 9 жовтня 2026 року, тому код, який читає старі файли без encoding, краще перевірити вже зараз.
З датою була невелика плутанина. Третій реліз-кандидат 3.15.0rc3 вийшов 2 жовтня, а фінальну версію перенесли з 1 на 9 жовтня через останні виправлення в лінивих імпортах. Про інше нововведення цього випуску, вибірковий профайлер Tachyon, ми писали раніше.
Що саме змінює PEP 686
Зміну описує PEP 686 (Python Enhancement Proposal, пропозиція щодо вдосконалення Python). Режим UTF-8 тепер увімкнений за замовчуванням: коли аргумент encoding не передано, Python не звертається до локалі системи. У UTF-8 кирилична літера займає два байти, у cp1251 — один, тому той самий файл без правильного кодування перетворюється на набір дивних символів.
Без явного кодування за UTF-8 тепер працюють такі виклики:
- відкриття текстових файлів через
open(); - методи
Path.read_text()іPath.write_text()модуля pathlib; - текстові режими функцій
gzip.open(),bz2.open()іlzma.open(); - виклики subprocess із параметром
text=True; - читання через configparser і запис через logging.FileHandler.
На Windows зміна зачіпає й перенаправлені потоки введення та виведення, тоді як консоль і раніше працювала в UTF-8. На Linux і macOS різниці майже не буде, бо UTF-8 там давно стандартна локаль. Винятком лишаються контейнери без налаштованої локалі (C або POSIX): там замість ascii тепер теж UTF-8.
Що таке режим UTF-8 в інтерпретаторі
Режим UTF-8 — це налаштування Python, за якого інтерпретатор ігнорує локаль системи й використовує UTF-8 як кодування за замовчуванням. Увімкнути або вимкнути його можна лише під час запуску програми, а поточний стан показує значення sys.flags.utf8_mode.
Що буде зі старими файлами
Найбільше зміна вдарить по файлах, збережених у cp1251: старих текстових даних, експортах із застарілих програм, журналах. Якщо читати їх без encoding, Python тепер очікуватиме UTF-8. Автори PEP 686 попереджають про три можливі наслідки: виняток UnicodeError, кракозябри й навіть тиху порчу даних.
Файл не знає, де його відкриють, тому кодування краще вказувати в коді, а не залишати на волю налаштувань комп'ютера.
У таблиці порівняно, як поводиться виклик без аргументу encoding до виходу Python 3.15 і після нього.
| Ситуація | До Python 3.15 | У Python 3.15 |
|---|---|---|
| Windows із кириличною локаллю | cp1251 | utf-8 |
| Linux або macOS з UTF-8 | utf-8 | utf-8 |
| Контейнер із локаллю C або POSIX | ascii | utf-8 |
| Кодування вказано в коді | як вказано | як вказано |
Рядок про явне кодування найважливіший. Саме він показує, що надійний код від релізу не залежить.
Помилка замість кракозябр
Покажемо це на прикладі. Створимо файл old_cp1251.txt із текстом «Привіт, світе» у кодуванні cp1251 і прочитаємо його так, як це робитиме Python 3.15 без аргументу encoding:
with open("old_cp1251.txt", encoding="utf-8") as f:
print(f.read())
# UnicodeDecodeError: 'utf-8' codec can't decode byte 0xcf in position 0: invalid continuation byte
Помилка принаймні помітна одразу. Гірше, коли дані йдуть у протилежний бік: текст у UTF-8, прочитаний як cp1251, дає рядок «РџСЂРёРІС–С‚, світе» — той самий «Привіт, світе», тільки зіпсований. Саме так поводився Python на Windows із кириличною локаллю, а тепер такий файл читається правильно.
Як знайти проблемні місця
Знайти виклики без encoding допоможуть вбудований механізм попереджень і лінтер (програма статичної перевірки коду). Обидва способи працюють уже на поточних версіях Python, тому чекати релізу не потрібно. Щоб підготувати проєкт до 3.15, виконайте такі кроки:
- Запустіть скрипт або тести з прапорцем
-X warn_default_encoding: кожен текстовий виклик без encoding покаже EncodingWarning. - Якщо змінювати команду запуску незручно, задайте змінну середовища
PYTHONWARNDEFAULTENCODINGзі значенням 1. - Встановіть плагін flake8-encodings: він позначає такі виклики кодом ENC001.
- Для файлів у UTF-8 додайте до кожного виклику
encoding="utf-8". - Для старих файлів у cp1251 вкажіть
encoding="cp1251"або один раз перекодуйте їх у UTF-8. - Окремо перевірте виклики subprocess із text=True: там кодування теж потрібно вказати явно.
Бінарний режим файлів і стандартні потоки в перевірку не потрапляють, тож зайвого шуму не буде. На Linux і macOS попередження все одно з'являються, і це корисно для коду, який має працювати на будь-якій системі.
Як повернути старе кодування
Зворотний хід лишається доступним, але це тимчасовий засіб. Змінна середовища PYTHONUTF8 зі значенням 0 або параметр -X utf8=0 вимикають режим UTF-8 і повертають кодування за локаллю на весь запуск. У PowerShell це виглядає так:
PS> $env:PYTHONUTF8="0" PS> py -3.15 script.py
Надійніше вказувати потрібне кодування в кожному виклику, бо змінна середовища на іншому комп'ютері може бути відсутня. Для окремого виклику підійде encoding="locale" (з Python 3.10): він свідомо залишає кодування системи. Щоб дізнатися справжнє кодування локалі, використовуйте locale.getencoding() (з Python 3.11), бо locale.getpreferredencoding(False) тепер повертає utf-8.
Python приєднується до інших мов: Ruby перейшов на UTF-8 за замовчуванням на Windows у версії 3.0 ще 2020 року, а Java зробила це у версії 18. Станом на 5 жовтня 2026 року фінальний реліз Python 3.15 ще попереду, тож є час пройтися по проєктах із кириличними даними й додати encoding туди, де його бракує. Напишіть у коментарях, які файли у ваших скриптах досі лежать у cp1251.
Схожі публікації