Python 3.15 has reached Release Candidate 1, with the final release currently expected on October 1, 2026. I went through the changes and pulled out the ones that seem most relevant to everyday development.
The highlights include opt-in lazy imports for reducing startup overhead, UTF-8 becoming the default encoding for operations such as opening files without an explicit encoding, a built-in immutable mapping similar to frozendict, continued JIT improvements, and a new low-overhead sampling profiler called Tachyon that can attach to an already-running process. The interactive interpreter is also getting improvements such as colored prompts and errors, while the sqlite3 command-line tool gains SQL keyword completion.
The free-threaded build remains opt-in rather than becoming the default, although ABI improvements should make it easier for C extension developers to support. Comprehensions and generator expressions can also use starred unpacking, and there are some smaller additions such as sentinel support.
Overall, this looks more like a performance, tooling, and developer-experience release than a major change to Python syntax or style. Has anyone tested the beta or RC in a real project? I'm especially interested in whether lazy imports cause problems for frameworks that depend on import-time side effects or initialization order.
5 Answers
A low-overhead profiler that can attach to an already-running process sounds genuinely practical. It should make it easier to investigate production-like performance problems without restarting the application under a profiler. The main questions for me are how its results compare with existing sampling tools and whether attaching requires elevated permissions.
I’d be cautious about adopting the release immediately for large applications. Release candidates are specifically meant to uncover compatibility problems, and packages with native extensions may take time to catch up. Keeping free-threading opt-in seems sensible while the ecosystem continues adding support.
That’s my approach too: test the RC in an isolated environment, but wait for the final release and package support before upgrading anything critical.
The UTF-8 change should eliminate a lot of avoidable cross-platform surprises. File I/O without an explicit encoding has traditionally depended on the locale, which commonly meant UTF-8 on Linux but a different default on Windows. I’ll still keep specifying encoding explicitly in code where the file format matters.
Same here. It’s a useful safer default, but being explicit is still clearer when compatibility with older Python versions or a particular file format matters.
The immutable mapping sounds useful, but it solves a different problem from a read-only mapping proxy. A proxy is a live view of another dictionary, so changes to the original remain visible. An immutable mapping is its own fixed value and can be hashable when all its contents are hashable, making it suitable for constants, dictionary keys, or set members. I wouldn’t assume either is faster without seeing focused benchmarks.
Lazy imports are the feature I’d be most interested in trying on a real project. They could make a noticeable difference for command-line tools and smaller services with large dependency trees, but libraries that do metaprogramming or other work at import time might need careful testing.
They’re opt-in, so ordinary import statements should keep their current behavior. The main compatibility questions apply to code that explicitly chooses lazy imports.
That makes sense. I’d benchmark startup time and run the full test suite before assuming the change improves an existing application.

I’ve used a process-attached Python sampler for a similar workflow, and the ability to see live function activity is extremely useful. Avoiding extra permissions would make this kind of tool much easier to use routinely.