Python 3.15 was supposed to be the least surprising news of the month. The feature set has been locked since May, and our preview series has been walking through it all summer. Then a handful of last-minute bugs in lazy imports forced a surprise third release candidate, and the final release moved to October 9, later this week.

The first-ever Python Packaging Council was elected and immediately handed a PEP written by one of its own members. PyPI changed how it counts downloads, so if your package’s chart just fell off a cliff, that’s the likely reason.

Polars 2.0 reached the release candidate stage with a new default that can reorder your rows, and SQLAlchemy 2.1 shipped in late September. Meanwhile, the AI providers broke Python code again, this time from the API side, and EVE Online announced that its 2.4 million lines of Python 2 are finally moving to Python 3.

Grab a coffee, because there’s a lot of Python news to get through!

Python 3.15 Gets a Surprise RC3

Python 3.15.0 was due on October 1, the date that PEP 790 set for it more than a year ago. Instead, release manager Hugo van Kemenade announced a third release candidate, explaining that “we got some last-minute lazy-import release blockers, and it makes sense to include them in 3.15.0 final.”

Python 3.15.0rc3 came out on October 2 with around 156 fixes from 82 contributors since rc2. The final release is now scheduled for Friday, October 9.

The blockers were the kind of edge cases you only find once people start using a feature for real. In one bug, lazy import a.b as c treated b as an attribute of a instead of importing the a.b submodule. In another, touching one lazily imported submodule of a package also imported a sibling submodule that should have stayed lazy. Shipping a headline feature with known bugs like these would’ve been worse than a one-week delay.

Nothing else changes. The feature set has been frozen since May. The application binary interface (ABI), which compiled extensions rely on to work with the interpreter, has been frozen since August and stays frozen through rc3. Between now and Friday, only reviewed bug fixes can land on the 3.15 branch. If you followed the release candidates over the summer, then nothing in the final build will surprise you.

You can try the release candidate in a REPL today without installing anything by hand, as long as your copy of uv is recent enough to know about rc3. Once the final release is out, an updated uv will pick up 3.15.0 with the same command:

Language: Shell
$ uv self update $ uv run --python 3.15 python 

If you installed uv through a package manager like Homebrew or pipx, then uv self update won’t work, so upgrade uv with that package manager instead.

Once you’re in, most of the headline features fit on a single screen. Here’s a lazy import, a frozen dictionary, and a sentinel working together:

Language: Python
>>> lazy import json >>> import sys >>> "json" in sys.modules False >>> defaults = frozendict({"theme": "light", "autosave": True}) >>> MISSING = sentinel("MISSING") >>> defaults.get("font", MISSING) MISSING >>> json.dumps(defaults | {"theme": "dark"}) '{"theme": "dark", "autosave": true}' >>> "json" in sys.modules True 

The lazy soft keyword from PEP 810 defers the import until you first access json, which is why the module shows up in sys.modules only after the .dumps() call. The frozendict and sentinel built-ins are the two new types: one for mappings that can’t change and one for marking missing values when None is a valid value.

Lazy imports are also the feature that rc3 fixed, so if you tried them on rc2 and saw a submodule load too early or not at all, then try again on rc3.

Beyond those three, the release has these additions:

  • UTF-8 by default now applies everywhere, so open() stops guessing your encoding from the system locale.
  • A sampling profiler in the standard library can attach to a running process.
  • An upgraded just-in-time (JIT) compiler adds a tracing frontend. It’s still experimental and runs only in builds that support it and have it enabled. In the core team’s benchmarks, it’s 7 to 8 percent faster than the standard interpreter on x86-64 Linux and 11 to 12 percent faster than the tail-calling interpreter on AArch64 macOS.
  • A tail-calling interpreter in the official 64-bit Windows binaries is built with Visual Studio 2026. In pyperformance runs on x86-64, it measured 15 to 20 percent faster than the switch-case interpreter.
  • abi3t is a stable ABI for the free-threaded build. A C extension that opts in can ship one wheel for free-threaded Python 3.15 and later, though common build tools can’t produce these wheels yet.
  • TypeForm and closed TypedDict types arrive for anyone who argues with their type checker for fun.
  • Unpacking in comprehensions now works, as in {**profile for profile in profiles}.

One more change is a retreat rather than a feature. The incremental garbage collector that debuted in 3.14.0 was rolled back in 3.14.5 after reports of memory pressure, and 3.15 keeps the older generational collector. It’s the second time that design has been pulled, and it’s a useful reminder that a good benchmark isn’t the same as a good production week.

Should you upgrade this week? Test on rc3 now, and switch your own scripts and command-line tools once 3.15.0 lands on Friday. Lazy imports alone can make a sluggish --help feel snappy again. If you maintain a package with compiled extensions, then you don’t have to wait. Wheels built against the release candidates are compatible with the final release, so you can publish 3.15 wheels today.

For anything you deploy, the usual advice still applies: wait until your compiled dependencies publish 3.15 wheels, and let production servers sit tight until 3.15.1. The one change most likely to bite is the switch to UTF-8 by default, which matters only if your code implicitly relied on a legacy locale. Your test suite will tell you in an afternoon, and you don’t need to wait for Friday to run it:

Language: Shell
$ uv run --isolated --python 3.15 --with pytest==9.1.1 \  python -X warn_default_encoding -m \  pytest -W error::EncodingWarning 

In a uv project, that command builds a throwaway 3.15 environment from your pyproject.toml and adds pytest in case it isn’t already a dependency.

Read the full article at https://realpython.com/python-news-october-2026/ »


[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]