Python 3.15 Is Out: What's New and How to Update

Python 3.15.0 is officially available today, bringing lazy imports, a frozendict type, UTF-8 by default, and a new profiling package. Here's what changed and how to upgrade.

Official Python logo wordmark with the two-tone blue and yellow snake icon
Image: Python Software Foundation.

Python 3.15.0 is officially out. The Python core development team released the final build on October 9, 2026, exactly on the schedule set out in PEP 790, and it's available now for Windows, macOS, and source builds from python.org. The headline changes are explicit lazy imports, a new immutable frozendict type, unpacking inside comprehensions, UTF-8 as the default text encoding, and a standalone profiling package with a high-frequency sampling profiler called Tachyon. Below is a rundown of what actually changed, pulled from the official release notes, and a straightforward path to updating.

Python 3.15.0 Is Officially Released

After months as a release candidate, Python 3.15.0 moved to final status today. The official release page lists October 9, 2026 as the release date, with installers for Windows (64-bit) and macOS, plus the source tarball for Linux and other Unix systems that build from source. This is the first stable release in the 3.15 line, meaning it now receives full bugfix support, and it starts the clock on 3.15's roughly two-year window of active maintenance before it moves to security-only fixes.

This follows directly from Pandromeda's earlier coverage of the scheduled October 9 release date. That piece covered what was planned; this one covers what actually shipped and how to get it running.

The Biggest Language Changes

Several of 3.15's changes touch how Python code is written and imported, not just how fast it runs.

  • Explicit lazy imports (PEP 810). A new lazy soft keyword lets you write lazy import json or lazy from pathlib import Path at module scope. The module isn't actually loaded until the first time an attribute on it is accessed, which can meaningfully cut startup time for programs that import a lot of modules they don't always use. It's opt-in: nothing changes unless you use the keyword, pass -X lazy_imports, or set the PYTHON_LAZY_IMPORTS environment variable. Wildcard lazy imports (lazy from module import *) and lazy __future__ imports are disallowed and raise a SyntaxError.
  • Unpacking inside comprehensions (PEP 798). The * and ** unpacking operators now work directly inside list, set, dict, and generator comprehensions, including async ones. [*row for row in rows] flattens a list of lists without a separate helper function or nested loop.
  • UTF-8 as the default text encoding (PEP 686). Calls to open() and other text I/O that don't specify an encoding argument now default to UTF-8 everywhere, rather than falling back to whatever the operating system's locale happens to be. This mainly affects Windows, where the previous locale-dependent default was a long-running source of "works on my machine" encoding bugs. Code that needs the old behavior can set PYTHONUTF8=0 or pass -X utf8=0.
  • frozendict, a built-in immutable mapping (PEP 814). frozendict is hashable when its keys and values are hashable, compares equal regardless of insertion order, and is accepted by json, pickle, copy, and pprint, among other standard library modules. It inherits directly from object, not from dict.
  • sentinel, a built-in for unique marker values (PEP 661). Sentinel objects get a readable repr(), keep their identity through copy/deepcopy, and work with the | union operator in type hints — replacing the common _SENTINEL = object() pattern with something the standard library understands natively.

Smaller syntax changes include unary + now being valid in match literal patterns (mirroring the existing support for unary -), __slots__ support for tuple subclasses, and the ability to declare __dict__ or __weakref__ via __slots__ on any class. The built-in slice type is also now generic and subscriptable.

Performance and Interpreter Changes

3.15 continues the multi-release push (started with the 3.11–3.13 adaptive interpreter and 3.13's experimental JIT) toward a faster CPython, with several changes aimed at profiling and native performance rather than headline throughput numbers:

  • Frame pointers on by default (PEP 831). On supported platforms, CPython is now built with -fno-omit-frame-pointer. This makes native stack traces from tools like perf and eBPF-based profilers reliable without a special debug build, which matters for anyone profiling Python services in production.
  • Startup configuration via .start files (PEP 829). Packages can now register entry points in the form pkg.mod:callable that run automatically at interpreter startup. At the same time, the older trick of putting bare import lines in .pth files is now silently deprecated.
  • Platform-specific build changes. Official Windows 64-bit binaries now use the tail-calling interpreter build, and official macOS binaries ship with free-threading support installed by default, continuing the free-threaded CPython work introduced in 3.13.

The official What's New in Python 3.15 document does not publish specific benchmark percentages for this release, so treat any such numbers you see elsewhere with some skepticism until you've measured your own workload.

A New Profiling Package, Plus the Tachyon Sampler

One of the more practically useful additions is a dedicated profiling package (PEP 799), which splits profiling into two pieces: profiling.tracing, the deterministic profiler moved over from cProfile (which remains available as an alias), and profiling.sampling, a brand-new statistical sampling profiler nicknamed Tachyon.

Tachyon can attach to an already-running process and sample it at up to 1,000,000 Hz without requiring any code changes or restart. It supports wall-clock, CPU, GIL-contention, and exception sampling modes, and can export results as pstats data, flamegraphs, Gecko profiles, or heatmaps, with live and async-aware modes for inspecting running asyncio applications. For teams that have been reaching for third-party samplers to profile production Python services without the overhead of a tracing profiler, this folds that capability into the standard library.

The older top-level profile module is now deprecated and is scheduled for removal in Python 3.17, so projects still importing it directly should plan a move to the profiling package.

Typing: TypedDict, TypeForm, and Disjoint Bases

The typing system picked up several refinements in 3.15, continuing the pattern of each release tightening up static-typing edge cases that mypy, pyright, and other checkers have to handle:

  • Typed extra items in TypedDict, letting you specify a type for keys beyond the explicitly declared ones instead of falling back to Any.
  • TypeForm, a way to annotate values that represent type expressions themselves (for example, a variable that holds int | str as a runtime value, used by validation and serialization libraries).
  • Disjoint bases, giving the type system a clearer way to reason about classes that intentionally cannot share a common instance.

These are primarily relevant to library authors and anyone leaning heavily on static type checking; they don't change runtime behavior for typical application code.

Standard Library and C API Highlights

Beyond the headline items, a long list of smaller library changes landed in 3.15:

  • base64 and binascii gain padded, wrapcol, ignorechars, and canonical parameters, plus new Base32, Ascii85, Base85, and Z85 encoding functions.
  • subprocess.Popen.wait(timeout=...) now uses event-driven waiting (pidfd/poll on Linux, kqueue on BSD and macOS) instead of polling in a loop.
  • json.load()/loads() gain an array_hook parameter; combined with frozendict as the object_pairs_hook, it's now possible to deserialize JSON into fully immutable data structures.
  • tomllib now supports TOML 1.1.0.
  • ssl adds set_groups(), set_ciphersuites(), and new signature-algorithm configuration methods.
  • bytearray.take_bytes() returns a bytes object without copying the underlying buffer.
  • re.prefixmatch() is added as a clearer-named alternative to re.match(), which is now softly discouraged in favor of the new name.
  • Colorized output extends to argparse, ast, calendar, difflib, http.server, pickletools, sqlite3, timeit, tokenize, and python --help.
  • A new top-level math.integer module groups mathematical functions specifically for integer arguments.
  • On the C API side, 3.15 adds a stable ABI for free-threaded builds (abi3t), a new PyBytesWriter API for building bytes objects, and interpreter guards that protect C API calls from running during interpreter finalization.

Error messages also got another pass: AttributeError can now suggest nested attributes (for example, hinting at .inner.area when you typed .area), and common method names from other languages produce targeted hints — calling .push() on a list suggests .append(), and calling .put() on a dict suggests the correct d[k] = v syntax.

AreaWhat changed in 3.15Reference
ImportsExplicit lazy import keyword for deferred module loadingPEP 810
Syntax*/** unpacking allowed inside comprehensionsPEP 798
Text I/OUTF-8 is now the default encoding everywhere, including WindowsPEP 686
Built-in typesNew frozendict (immutable dict) and sentinel typesPEP 814 / PEP 661
ProfilingNew profiling package with the Tachyon sampling profilerPEP 799
Native performanceFrame pointers on by default for reliable native stack tracesPEP 831
Securitytarfile fixes for five CVEs affecting extraction and symlinksSee Security section below
Deprecatedprofile module (removal in 3.17), import lines in .pth filesChangelog

Security Fixes in tarfile

The release notes list five tarfile-related CVE fixes bundled into 3.15:

  • CVE-2025-4138: data_filter() now normalizes symlink targets to prevent path traversal during extraction.
  • CVE-2024-12718: extractall() no longer applies directory attribute fixes when a directory entry was actually replaced by a different kind of file.
  • CVE-2025-4330: extract()/extractall() re-apply the extraction filter when substituting links with file copies, raising a new LinkFallbackError if that fails.
  • CVE-2025-4435: Members rejected by a filter are no longer extracted even when errorlevel is set to 0.
  • CVE-2025-4517: A new os.path.realpath(strict=os.path.ALLOW_MISSING) option was added to support safer path resolution.

None of these require code changes to benefit from — they're fixed at the standard library level once you're running 3.15 — but if your project extracts untrusted archives, it's a solid reason to prioritize the update.

Deprecations and Removals to Know About

A few things that used to work now emit warnings or have been removed outright:

  • The profile module is deprecated and will be removed in Python 3.17; use the new profiling package instead.
  • Bare import lines inside .pth files are now silently deprecated in favor of the new .start file mechanism.
  • The __cached__ module attribute has been removed; use __spec__.cached instead.
  • The PyGILState_* C API functions are soft-deprecated as part of the free-threading transition.
  • re.match() is softly discouraged in favor of the new, more clearly named re.prefixmatch().

As always with a .0 release, the full list of removed and deprecated APIs is longer than a single article can cover — check the official changelog if you maintain a large codebase before upgrading production systems.

A Caveat for macOS Users

The official release notes flag a specific interaction issue: on macOS 27.0, Tk-based applications — including IDLE, Python's bundled editor — may hang when opening certain dialogs. Python.org's guidance is to hold off on upgrading to macOS 27.0 if you rely on Tk-based tools until a workaround lands. This is an OS-level interaction issue, not a defect introduced by Python 3.15 itself, but it's worth knowing before you update both your OS and your Python version in the same sitting.

Quick upgrade checklist
  • Download the installer for your platform from python.org/downloads (Windows 64-bit .exe, macOS .pkg, or the source tarball for Linux/Unix).
  • Keep your existing Python installation in place — installers for new minor versions install side-by-side rather than overwriting.
  • Recreate virtual environments against the new interpreter (python3.15 -m venv .venv) rather than trying to upgrade an existing one in place.
  • Reinstall dependencies inside the new environment and run your test suite before switching any production workload over.
  • If you build CPython from source, ./configure, make, and make install against the 3.15.0 source tarball as usual.

How to Update to Python 3.15

Updating is the same process as any other Python minor-version release:

  • Windows: download the 64-bit installer from the Python 3.15.0 release page linked above and run it. Python's own install manager, distributed as an .msix package, can also manage multiple installed versions side by side.
  • macOS: download the .pkg installer from the same release page. See the python.org macOS downloads page for platform-specific notes, and keep the Tk/IDLE caveat above in mind if you're also on, or planning to move to, macOS 27.0.
  • Linux and other Unix systems: most distributions package Python separately from upstream and may not carry 3.15 yet; building from the official source tarball on the release page is the most direct way to get it immediately, following the standard ./configure && make && make install process.
  • Existing projects: new Python versions install alongside older ones rather than replacing them, so there's no rush to migrate everything the same day. Create a fresh virtual environment with the 3.15 interpreter, reinstall your dependencies into it, and run your test suite before pointing anything important at it.

If you maintain a published package, it's also worth checking that your classifiers and CI matrix are updated to cover 3.15, particularly if you rely on C extensions — the free-threading and stable-ABI changes in this release are most relevant to compiled extension modules rather than pure-Python code.

Frequently Asked Questions

When was Python 3.15 released? Python 3.15.0 was released on October 9, 2026, per the official python.org release page.

What's the single biggest change in this release? There isn't one standout change so much as a cluster of them: explicit lazy imports (PEP 810), UTF-8 becoming the default text encoding (PEP 686), and the new immutable frozendict type (PEP 814) are the three most likely to affect everyday code.

How do I update to Python 3.15? Download the Windows or macOS installer from python.org, or build from the source tarball on Linux/Unix. New versions install side by side with older ones, so create a fresh virtual environment with the 3.15 interpreter rather than upgrading an existing one in place.

Does Python 3.15 remove anything I might rely on? The __cached__ module attribute has been removed, the profile module is deprecated ahead of removal in 3.17, and bare import lines in .pth files are now deprecated. Check the official changelog before upgrading a large codebase.

Is there a known issue with Python 3.15 on macOS? The release notes warn that Tk-based applications, including IDLE, may hang when opening dialogs on macOS 27.0, and recommend holding off on that OS upgrade until a fix is available.

What's Next

Python 3.15.0 starts its support clock today; expect the first bugfix release, 3.15.1, within the next couple of months as early adopters report issues, following the cadence set by prior releases. Python 3.14 continues to receive bugfix support in the meantime, so there's no urgency to move production systems off it immediately. If you haven't already, the official What's New in Python 3.15 page linked above is the authoritative reference for every change mentioned here, with far more detail on each item than fits in a news roundup. For background on how this release's date was set, see Pandromeda's earlier coverage of the October 9 release schedule, and if you're also updating your editor alongside your interpreter, our recent look at what's new in VS Code covers the editor side of a typical Python developer's toolchain.

Frequently asked questions

When was Python 3.15 released?

Python 3.15.0 was released on October 9, 2026, according to the official python.org release page.

What's the single biggest change in Python 3.15?

There isn't one standout change so much as a cluster of them: explicit lazy imports (PEP 810), UTF-8 becoming the default text encoding (PEP 686), and the new immutable frozendict type (PEP 814) are the three most likely to affect everyday code.

How do I update to Python 3.15?

Download the Windows or macOS installer from python.org/downloads, or build from the source tarball on Linux/Unix. New versions install side by side with older ones, so create a fresh virtual environment with the 3.15 interpreter rather than upgrading an existing one in place.

Does Python 3.15 remove anything I might rely on?

The __cached__ module attribute has been removed, the profile module is deprecated ahead of removal in Python 3.17, and bare import lines in .pth files are now deprecated. Check the official changelog before upgrading a large codebase.

Is there a known issue with Python 3.15 on macOS?

Yes. The release notes warn that Tk-based applications, including IDLE, may hang when opening dialogs on macOS 27.0, and recommend holding off on that OS upgrade until a workaround is available.

Sources

More on Python →PythonPython 3.15CPythonProgramming LanguagesSoftware Updates
Felix Moreau
Written byFelix Moreau

Felix Moreau writes Pandromeda's software coverage and how-to guides. He covers Windows, macOS and Linux updates, the apps people rely on, emulators and developer tools, and turns official documentation into clear, numbered steps that work on the current version.

More from Software & Guides

See all