Python 3.15: nowości i co sprawdzić przed aktualizacją
Python 3.15.0 ukazał się 9 października 2026. Najważniejsze zmiany to jawne leniwe importy ze słowem lazy, wbudowany typ frozendict, UTF-8 jako domyślne kodowanie plików i szybszy interpreter w oficjalnych binariach dla Windows. Jednocześnie Python 3.10 przestał być wspierany, a z 3.15 usunięto funkcje przestarzałe od kilku wersji.
Opracowanie z użyciem narzędzi AI, na podstawie źródeł pierwotnych

Python 3.15.0 wyszedł 9 października 2026, osiem dni później, niż podawała strona wydania rc2 z 1 września. Na stronie wydania rc3 release manager Hugo van Kemenade wyjaśnił, że w ostatniej chwili pojawiły się błędy blokujące w leniwych importach i trzeba było je naprawić przed wydaniem finalnym. Poniżej opisujemy nowości, które zmieniają sposób pisania kodu, zmiany, które mogą zepsuć istniejące projekty, i kolejność kroków przed migracją.
1. Wydanie 3.15 i stan starszych wersji
Według PEP 790 wersja 3.15 dostaje poprawki błędów mniej więcej co dwa miesiące przez dwa lata, a potem same poprawki bezpieczeństwa do około października 2031. Wydanie obejmuje 5643 commity od 1012 osób.
Razem z premierą 3.15 zmienił się status starszych gałęzi. PEP 619 podaje, że 1 października 2026 Python 3.10 zakończył wsparcie, a ostatnim wydaniem jest 3.10.22. Tego samego dnia ukazał się Python 3.13.16, ostatnie wydanie tej gałęzi z instalatorami binarnymi. Od teraz 3.13 dostaje tylko poprawki bezpieczeństwa w postaci kodu źródłowego.
| Wersja | Status w październiku 2026 | Koniec wsparcia |
|---|---|---|
| 3.15 | poprawki błędów | październik 2031 |
| 3.14 | poprawki błędów | październik 2030 |
| 3.13 | tylko bezpieczeństwo | październik 2029 |
| 3.12 | tylko bezpieczeństwo | październik 2028 |
| 3.11 | tylko bezpieczeństwo | październik 2027 |
| 3.10 | koniec wsparcia | 1 października 2026 |
Daty pochodzą z przewodnika dla deweloperów CPython i PEP poszczególnych wersji. Jeśli projekt nadal działa na 3.10, nie dostanie już żadnych poprawek, także bezpieczeństwa.
2. Leniwe importy ze słowem lazy
Największa nowość składni to PEP 810. Nowe miękkie słowo kluczowe lazy odkłada załadowanie modułu do chwili, gdy kod pierwszy raz użyje zaimportowanej nazwy. Do tego czasu nazwa wskazuje lekki obiekt pośredniczący typu types.LazyImportType.
lazy import json
lazy from pathlib import Path
def zapisz(dane):
return json.dumps(dane) # moduł json ładuje się dopiero tutaj
Według What’s New lazy działa tylko na poziomie modułu. Użyte w funkcji, klasie albo bloku try, except lub finally daje SyntaxError, podobnie jak lazy from x import *. Błąd ładowania, na przykład brak modułu, pojawia się w miejscu pierwszego użycia, a traceback pokazuje też linię z instrukcją importu.
Leniwość da się też włączyć globalnie opcją -X lazy_imports=all albo zmienną PYTHON_LAZY_IMPORTS=all, a z poziomu kodu funkcjami sys.set_lazy_imports() i sys.set_lazy_imports_filter(). Kod, który musi działać także na starszych wersjach, może zdefiniować listę __lazy_modules__ = ["json", "pathlib"]. Wtedy zwykłe import json jest leniwe w 3.15, a starsze interpretery ignorują tę listę.
PEP 810 podaje, że w innych implementacjach leniwe importy skracały start programów o 50 do 70% i zmniejszały zużycie pamięci o 30 do 40%. To dane z uzasadnienia PEP, nie pomiary CPython 3.15, więc zysk w twoim projekcie trzeba zmierzyć samodzielnie.
3. frozendict, sentinel i rozpakowanie w wyrażeniach
PEP 814 dodaje wbudowany typ frozendict, czyli niemodyfikowalny słownik. Da się go haszować, jeśli klucze i wartości są haszowalne, więc może być kluczem innego słownika albo elementem zbioru. Zachowuje kolejność wstawiania, ale porównanie dwóch obiektów jej nie uwzględnia. Operator | zwraca nowy obiekt. Ważne przy migracji jest to, że frozendict nie jest podklasą dict, więc warunek isinstance(x, dict) go odrzuci. What’s New zaleca w takich miejscach isinstance(x, (dict, frozendict)) albo collections.abc.Mapping.
Nowy wbudowany typ sentinel z PEP 661 służy do tworzenia wartości oznaczających „brak argumentu”, gdy None jest poprawną wartością. Taki obiekt porównujesz przez is, a copy, deepcopy i pickle zachowują jego tożsamość.
MISSING = sentinel("MISSING")
def pobierz(klucz, domyslna=MISSING):
if domyslna is MISSING:
...
PEP 798 pozwala rozpakowywać w wyrażeniach listowych. Zapis [*L for L in listy] spłaszcza listę list bez itertools.chain.from_iterable, a {**d for d in slowniki} łączy słowniki, przy czym przy powtórzonym kluczu wygrywa ostatnia wartość.
4. UTF-8 domyślnie i co to znaczy na Windows
Ta zmiana może dotknąć najwięcej istniejącego kodu. Zgodnie z PEP 686 operacje na plikach bez argumentu encoding, na przykład open("dane.txt"), używają teraz UTF-8 niezależnie od ustawień systemu. Wcześniej używały kodowania z ustawień regionalnych.
PEP 686 wprost ostrzega, że zmiana może powodować UnicodeDecodeError, błędnie wyświetlane znaki, a nawet ciche uszkodzenie danych. Najbardziej dotyczy Windows, bo większość systemów Unix ma już ustawienia regionalne w UTF-8. W praktyce chodzi o skrypty, które czytają albo zapisują pliki tekstowe bez podania kodowania, a pliki powstały w kodowaniu regionalnym systemu, takim jak Windows-1250 dla języków środkowoeuropejskich.
Rozwiązaniem jest jawne encoding w każdym open(). Jeśli potrzebujesz kodowania z ustawień systemu, podaj encoding="locale", dostępne od Pythona 3.10. Stare zachowanie całego interpretera przywrócisz zmienną PYTHONUTF8=0 albo opcją -X utf8=0. Miejsca bez jawnego kodowania wskaże ostrzeżenie EncodingWarning, które włączasz opcją -X warn_default_encoding.
5. Wydajność, JIT i profilowanie
Oficjalne 64-bitowe binaria dla Windows są budowane w Visual Studio 2026 i używają interpretera „tail-calling”. What’s New podaje dla nich średnio 15 do 20% przyspieszenia w testach pyperformance względem dotychczasowego interpretera. Wynik zależy od rodzaju kodu i wynosi od 14% dla dużych bibliotek do 40% dla małych, długo działających skryptów.
Eksperymentalny kompilator JIT według What’s New przyspiesza kod średnio o 7 do 8% na x86-64 z Linuksem i o 11 do 12% na AArch64 z macOS. Rozrzut jest jednak duży, od około 15% spowolnienia do ponad 100% przyspieszenia w zależności od testu. JIT nadal jest eksperymentalny i przy budowaniu ze źródeł domyślnie wyłączony.
Do analizy wydajności przyda się nowy pakiet profiling z PEP 799. Zawiera profiler deterministyczny profiling.tracing i próbkujący profiling.sampling, nazwany Tachyon, który podłącza się do działającego procesu i próbkuje do 1 000 000 razy na sekundę. Moduł profile jest przestarzały i zniknie w 3.17. Z kolei PEP 831 domyślnie włącza wskaźniki ramek (frame pointers), co ułatwia profilowanie narzędziami systemowymi.
6. Co usunięto i co może zepsuć kod
Sekcja „Removed” w What’s New obejmuje funkcje oznaczone wcześniej jako przestarzałe. Najczęściej spotkasz je w starszym kodzie:
http.server: usunięteCGIHTTPRequestHandleri flaga--cgi.importlib: usunięte metodyload_module()w loaderach, a takżezipimporter.load_module().- moduły
sre_compile,sre_constantsisre_parseusunięte w całości. typing: koniec składniNamedTuple("Point", x=int, y=int)i usunięty dekoratorno_type_check_decorator.datetime.strptime(): format z%dbez roku zgłaszaValueError.pathlib.PurePath.is_reserved(): usunięte, zamiennikiem jestos.path.isreserved().ast: konstruktory węzłów zgłaszająTypeErrorprzy brakującym wymaganym argumencie.
Sekcja „Porting to Python 3.15” opisuje zmiany zachowania bez usuwania funkcji. W sqlite3.connect() wszystkie parametry poza database trzeba podawać nazwą. W argparse wywołanie add_argument("-f", "-foo") daje teraz dest równe "foo", a nie "f". base64.urlsafe_b64decode() nie wymaga już dopełnienia, a unittest.assertWarns() przestał połykać niepasujące ostrzeżenia, więc w testach mogą pojawić się ostrzeżenia, których wcześniej nie widziałeś.
Zmiana dotyczy też plików .pth. PEP 829 wprowadza pliki .start z funkcjami wywoływanymi przy starcie interpretera. Linie import w .pth działają do 3.17, ale są ignorowane, gdy istnieje pasujący plik .start. Od 3.20 będą ignorowane z ostrzeżeniem.
7. Jak sprawdzić projekt przed aktualizacją
Najprostszy test to uruchomienie testów projektu na 3.15 z ostrzeżeniami o kodowaniu i przestarzałych funkcjach zamienionymi w błędy. Opcje -X warn_default_encoding i -W error::DeprecationWarning są opisane w dokumentacji wiersza poleceń Pythona.
python3.15 -X warn_default_encoding -W error::DeprecationWarning -m pytest
python3.15 -X lazy_imports=all -m pytest
Drugie polecenie wymusza leniwe ładowanie wszystkich importów i pokazuje, czy kod polega na efektach ubocznych importu, na przykład rejestracji wtyczek. Na Windows przejrzyj osobno wszystkie wywołania open() bez encoding, bo zmiana z sekcji 4 nie musi wywołać błędu, tylko dać źle odczytane znaki. Sprawdź też, czy zależności z rozszerzeniami w C mają już pakiety wheel dla 3.15. PEP 803 dodaje osobne stabilne ABI abi3t dla wersji bez GIL.
8. Wersja bez GIL
Wersja free-threaded, czyli bez globalnej blokady interpretera, jest oficjalnie wspierana od Pythona 3.14 zgodnie z PEP 779. Domyślną wersją CPython 3.15 nadal jest interpreter z GIL, bo zmiana domyślnego trybu wymaga osobnego PEP. Nowością w 3.15 jest to, że według strony wydania oficjalne instalatory dla macOS domyślnie instalują obsługę free-threading. Na macOS 27.0 strona wydania ostrzega też, że IDLE i inne aplikacje tkinter mogą się zawieszać przy poleceniach menu otwierających okno dialogowe.
9. Podsumowanie
Python 3.15 nie wymaga przepisywania kodu, ale dwie zmiany warto sprawdzić od razu. Domyślne UTF-8 dotyczy każdego open() bez kodowania i najbardziej skryptów na Windows. Z kolei lista usunięć uderza w starszy kod korzystający z importlib, sre_* i serwera CGI. Leniwe importy możesz wprowadzać stopniowo, a dzięki __lazy_modules__ także w kodzie, który nadal musi działać na starszych wersjach.
Najczęstsze pytania
Czy w Pythonie 3.15 JIT jest włączony domyślnie?
Nie. Kompilator JIT nadal jest eksperymentalny. Przy budowaniu ze źródeł opcja --enable-experimental-jit ma domyślnie wartość no, a wariant yes-off buduje JIT wyłączony, który włączasz zmienną PYTHON_JIT=1. Plan wspieranego JIT opisuje dopiero szkic PEP 836 dla Pythona 3.16.
Czy mogę używać leniwych importów w kodzie, który działa też na starszych wersjach?
Tak, ale nie słowem lazy, bo starsze wersje zgłoszą błąd składni. Zamiast tego zdefiniuj w module listę __lazy_modules__ z nazwami modułów. Python 3.15 importuje je leniwie, a starsze wersje traktują listę jak zwykłą zmienną i importują moduły od razu.
Dlaczego isinstance(x, dict) zwraca False dla frozendict?
Bo frozendict nie jest podklasą dict, dziedziczy bezpośrednio po object. Dokumentacja Pythona zaleca w takich miejscach isinstance(x, (dict, frozendict)) albo sprawdzanie collections.abc.Mapping.
Czy re.match() zostanie usunięte?
Nie. Python 3.15 dodaje re.prefixmatch() jako nową nazwę i oznacza re.match() jako miękko przestarzałe. To znaczy, że funkcja zostaje i nie ma planu jej usunięcia, a nowy kod może używać nowej nazwy.
Do kiedy Python 3.15 będzie wspierany?
Według PEP 790 wersja 3.15 dostaje poprawki błędów mniej więcej co dwa miesiące przez dwa lata, a potem tylko poprawki bezpieczeństwa, do około października 2031 roku.
Źródła
- Python Release Python 3.15.0, Python Software Foundation (2026)
- What's New In Python 3.15, Python Software Foundation (2026)
- PEP 790: Python 3.15 Release Schedule, Python Software Foundation (2026)
- PEP 810: Explicit lazy imports, Python Software Foundation (2025)
- PEP 814: Add frozendict built-in type, Python Software Foundation (2026)
- PEP 686: Make UTF-8 mode default, Python Software Foundation (2022)
- PEP 829: Package startup configuration files, Python Software Foundation (2026)
- PEP 779: Criteria for supported status for free-threaded Python, Python Software Foundation (2025)
- PEP 619: Python 3.10 Release Schedule, Python Software Foundation (2026)
- Status of Python versions, Python Software Foundation (2026)



