Software 44961 Published by

Python's core team dropped a surprise third release candidate, 3.15.0rc3, moving the stable build to October 9, 2026. The late candidate folds in last-minute lazy-import fixes, and the team stresses there will be no ABI changes from here on so existing binary wheels stay compatible. Highlights include explicit lazy imports, new frozendict and sentinel types, UTF-8 as the default encoding, a faster JIT, and a new Tachyon sampling profiler. Maintainers are urged to test on CI ahead of launch, though macOS 27.0 users should hold off as tkinter apps like IDLE can hang.



Python 3.15 gets a surprise third release candidate, stable release set for October 9

The core team has issued a third and final release candidate for Python 3.15, and the stable build is now planned for October 9, 2026.

The announcement landed on the Python Insider blog, where release manager Hugo van Kemenade laid out exactly what 3.15.0rc3 is and, more importantly, what it isn't. Keep in mind that this candidate came later than the original schedule intended.

Python

The delay was not a broken-build panic. The team folded in some last-minute lazy-import blockers and simply decided testers deserved more time to validate them. In its own framing, an extra surprise candidate is a responsible move, not a red flag. Python has pulled this trick before, apparently as a "recent tradition."

Here's the tally: rc3 packs around 156 bugfixes, build improvements, and documentation tweaks from 82 contributors since rc2. After this point the hardening rules take over. Only clear-cut bug fixes get accepted; new feature work waits for the next cycle.

One detail that should actually matter to the ecosystem is that there will be no ABI changes from here on. Binary wheels you build against this RC stay compatible with later 3.15 releases. So if you maintain a third-party library, what you test now is what will genuinely ship.

The headline changes

Python 3.15 is shaping up to be one of the more meaningful releases in a few years. The list includes lazy imports, two new built-in types, UTF-8 by default, and a notably bigger JIT. Let's walk through the parts you'll actually see in your code.

Explicit lazy imports (PEP 810). This is the marquee feature, and lazy imports specifically had been requested for years, with proposals bouncing around the bug tracker well before this PEP took shape. A new soft keyword lazy defers loading a module until you use it:

lazy import json

print("Starting up...")  # json not loaded yet
data = json.loads('{}')  # it loads here

That keeps your tidy top-of-file imports while making you pay the load cost only for what you touch. The PEP claims 50–70% faster startup for command-line tools and 30–40% memory savings in long-running processes. The mechanism leans on a lightweight proxy that reifies on first use, so once a module loads there is zero runtime overhead. It's opt-in and backwards compatible, which arguably matters more than the micro-benchmarks do.

Two new built-in types. frozendict (PEP 814) gives you a first-class immutable dict. It isn't a subclass of dict, stays hashable when its keys and values are, and ignores insertion order when comparing. The newer sentinel type (PEP 661) makes creating a "no value here" marker object painless, which the docs quietly acknowledge developers already hand-roll constantly.

UTF-8 by default (PEP 686). Text I/O now uses UTF-8 regardless of your system locale. You can still pass encoding= explicitly, or reach for PYTHONUTF8=0 to revert. This just aligns Python with how the web already works.

A couple of smaller but welcome touches: * and ** unpacking now works inside comprehensions (PEP 798), and new .start files (PEP 829) give you a cleaner, safer way to declare package startup entry points than the old .pth habit of running arbitrary code.

More speed, and a new profiler

The experimental JIT got a real overhaul, building against LLVM 21 and adding register allocation plus better constant propagation. On pyperformance you're looking at roughly a 7–8% geometric mean win on x86-64 Linux and 11–12% on AArch64 macOS. Individual benchmarks swing wildly, from a ~15% slowdown to over 100% faster depending on the workload.

Keep in mind you only need LLVM installed when building CPython with the JIT, not when merely running it.

The word "experimental" is still attached to the JIT, though. It's been experimental for a long time, and this update does make it feel less like a long-running science project than in past years.

Windows users get a separate boost. The official 64-bit installers now use a tail-calling interpreter, made possible by a new Visual Studio 2026 feature. That's a reported 15–20% faster on Windows x86-64, with the biggest gains showing up in long-running small scripts rather than heavy libraries.

Python 3.15 also pulls its profiling tools under a single profiling module (PEP 799). The star is Tachyon, a sampling profiler that attaches to a running process by PID and can sample at rates up to 1,000,000 Hz. That's fast enough that overhead stays near zero, which makes it genuinely useful for chasing production bugs without slowing the app down. It can emit pstats, collapsed stacks for flame graphs, or a self-contained interactive HTML graph, among other formats. The old cProfile stays as an alias, though the pure-Python profile module is now slated for removal in 3.17.

One caveat worth flagging before you upgrade. macOS 27.0 users report that IDLE and other tkinter GUI apps hang when opening a dialog through the application menu. The culprit is believed to be a macOS system change affecting the Tk toolkit across the board. If your day-to-day leans on Tk-based apps, you might hold off on macOS 27.0 until a workaround lands. The issue is tracked at cpython issue #158053.

Testing now, shipping October 9

There's plenty of smaller stuff too. AttributeError messages now get smart, suggesting Did you mean '.append' when you accidentally write JavaScript's .push() on a list. The interpreter even keeps a table of method names from other languages to cross-suggest, so .toUpperCase() becomes .upper. You'll also see colored help text and CLI output, a copy-free bytearray.take_bytes(), and a now-generic slice type.

And as always, some things have been yanked. The internal regex modules (sre_compile, sre_constants, sre_parse) are gone, http.server's CGI handler is gone, and other deprecated artifacts have finally been cut. The migration guide covers the subtler shifts, especially the UTF-8 default, which pass encoding= explicitly if you ever leaned on the system locale.

The team's message to library maintainers is straightforward: test now. Because those binary wheels stay compatible across the entire 3.15 series, publishing 3.15 wheels ahead of the final release is low-risk, high-reward. You can drop 3.15 into your GitHub Actions matrix with allow-prereleases: true, and flag support with the Programming Language :: Python :: 3.15 Trove classifier. Any issues found should go to the Python bug tracker.

None of that changes the usual prelease warning. 3.15.0rc3 is not for production. The stable 3.15.0 is planned for October 9, and the 3.15 line itself is expected to stay supported until roughly October 2031.

Head here to the change log and here to the download page.